【问题标题】:How to optimize a dateframe processing in pandas?如何优化熊猫中的数据框处理?
【发布时间】:2020-08-02 15:14:38
【问题描述】:

我有一个追随者。


    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

【问题讨论】:

    标签: pandas performance optimization jupyter-notebook


    【解决方案1】:

    groupby on 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
    

    一次性处理所有列:

    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
    

    【讨论】:

      【解决方案2】:
      • 财务数据通常采用标准格式,只有一个datetime 列,而不是datetime 列。
        • 我的假设是,datetime 被分离以促进 OP 提供的当前流程。
          • 如果是这种情况,请不要拆分列。
          • 确保datetime 列是datetime dtypedf.info()
      • 如果数据确实带有单独的列,最好将它们连接到datetimedtype
      • 使用datetime dtype 有许多.dt 方法可用于提取特定组件(例如.dt.date
      • 使用pandas.DataFrame.iat 访问所有列的第一行。
      • 这类似于来自Henry Yiksolution,除了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
      

      【讨论】:

      • 谢谢,我还不太喜欢 pandas,所以我更容易将日期和时间保存在 2 列中,您的解决方案也很有效!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-03
      • 1970-01-01
      • 2019-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多