Как оптимизировать обработку даты в pandas? - PullRequest
0 голосов
/ 02 августа 2020

У меня есть следующий DF.


    Date        Time        Open    High    Low     Close
0   2010-01-03  17:00:00    1.4301  1.4304  1.4301  1.4304
1   2010-01-03  17:01:00    1.4303  1.4303  1.4303  1.4303

Мне нужно нормализовать цены внутри каждого дня, поэтому необходимо разделить цену каждого дня на ее первое значение дня, чтобы каждый день начинался с 1.0. Я написал следующий код, но он работает очень медленно, как мне его улучшить? Я считаю это слишком сложным, есть ли элегантный способ?

for year in range(2010, 2021):
    for month in range(1, 13):
        for day in range(1, 31):
            mutdf = dfc.loc[(dfc['Date'].dt.year == year) & (dfc['Date'].dt.month == month) & (dfc['Date'].dt.day == day), 
                            ['Open', 'High', 'Low', 'Close']]
            if mutdf.empty:
                continue
            mutdf['Open'] = mutdf['Open'].divide(mutdf.iloc[0, 0])
            mutdf['High'] = mutdf['High'].divide(mutdf.iloc[0, 1])
            mutdf['Low'] = mutdf['Low'].divide(mutdf.iloc[0, 2])
            mutdf['Close'] = mutdf['Close'].divide(mutdf.iloc[0, 3])
            dfc.loc[(dfc['Date'].dt.year == year) & (dfc['Date'].dt.month == month) & (dfc['Date'].dt.day == day), 
                    ['Open', 'High', 'Low', 'Close']] = mutdf

Желаемый результат:

    Date        Time        Open    High    Low     Close
0   2010-01-03  17:00:00    1.00000 1.00000 1.00000 1.000000
1   2010-01-03  17:01:00    1.00014 0.99993 1.00014 0.999930
2   2010-01-03  17:02:00    1.00007 0.99993 1.00000 0.999930
3   2010-01-03  17:03:00    1.00007 0.99986 1.00007 0.999860
4   2010-01-03  17:04:00    1.00000 0.99986 0.99979 0.999720
5   2010-01-03  17:06:00    1.00000 0.99979 0.99993 0.999790
6   2010-01-03  17:08:00    0.99993 0.99986 0.99993 0.999790
7   2010-01-03  17:09:00    0.99993 0.99979 0.99979 0.999581
8   2010-01-03  17:10:00    0.99986 0.99979 0.99986 0.999790
9   2010-01-03  17:12:00    1.00007 0.99993 1.00007 0.999930

Ответы [ 2 ]

2 голосов
/ 02 августа 2020

groupby на Date и разделить на первое значение:

df["Open"] = df.groupby("Date")["Open"].transform(lambda d: d/d.iat[0])

print (df)

         Date      Time     Open    High     Low   Close
0  2010-01-03  17:00:00  1.00000  1.4304  1.4301  1.4304
1  2010-01-03  17:01:00  1.00014  1.4303  1.4303  1.4303

Работа со всеми столбцами в одном go:

col = ['Open', 'High', 'Low', 'Close']

print (df.set_index(["Date","Time"])
         .groupby("Date").apply(lambda d: d[col]/df[col].iloc[0])
         .reset_index())

         Date      Time     Open     High      Low    Close
0  2010-01-03  17:00:00  1.00000  1.00000  1.00000  1.00000
1  2010-01-03  17:01:00  1.00014  0.99993  1.00014  0.99993
1 голос
/ 02 августа 2020
  • Финансовые данные обычно представлены в стандартной форме с одним столбцом datetime, а не столбцами date и time.
    • Я предполагаю, что datetime был отделен, чтобы облегчить текущий процесс, представленный OP.
      • В этом случае не разделяйте столбец.
      • Убедитесь, что столбец datetime является datetime dtype с df.info()
  • Если данные поступают с отдельными столбцами, лучше объединить их в datetime dtype.
  • С datetime dtype есть многие .dt методы для извлечения определенного c компонента (например, .dt.date)
  • Используйте pandas.DataFrame.iat для доступа к первой строке из всех столбцов .
  • Это похоже на решение из Henry Yik , за исключением того, что столбец Datetime делает расчет groupby более простым.
import pandas as pd

data = {'Date': ['2010-01-03', '2010-01-03'], 'Time': ['17:00:00', '17:01:00'], 'Open': [1.4301, 1.4303], 'High': [1.4304, 1.4303], 'Low': [1.4301, 1.4303], 'Close': [1.4304, 1.4303]}
df = pd.DataFrame(data)

# convert Date to a datetime
df.Date = pd.to_datetime(df.Date)

# convert Time to a timedelta
df.Time = pd.to_timedelta(df.Time)

# create a single Datetime column
df['Datetime'] = df.Date + df.Time

# drop Date and Time
df = df.drop(columns=['Date', 'Time'])

# set Datetime as the index
df = df.set_index('Datetime')

# display(df)

                       Open    High     Low   Close
Datetime                                           
2010-01-03 17:00:00  1.4301  1.4304  1.4301  1.4304
2010-01-03 17:01:00  1.4303  1.4303  1.4303  1.4303

# groupby the date and normalize all rows
dfg = df.groupby(df.index.date).transform(lambda row: row/row.iat[0])

# display(dfg)

                        Open     High      Low    Close
Datetime                                               
2010-01-03 17:00:00  1.00000  1.00000  1.00000  1.00000
2010-01-03 17:01:00  1.00014  0.99993  1.00014  0.99993
...