【问题标题】:Pandas dataframe apply refer to previous row to calculate difference熊猫数据框应用参考上一行来计算差异
【发布时间】:2016-02-01 08:43:16
【问题描述】:

我有以下包含 2 列(简化)的熊猫数据框。第一列包含玩家姓名,第二列包含日期(datetime 对象):

  player    date
  A         2010-01-01
  A         2010-01-09
  A         2010-01-11
  A         2010-01-15
  B         2010-02-01
  B         2010-02-10
  B         2010-02-21
  B         2010-02-23

我想添加一列diff,它表示每个玩家的时差。结果应如下所示:

  player    date            diff
  A         2010-01-01      0
  A         2010-01-09      8
  A         2010-01-11      2
  A         2010-01-15      4
  B         2010-02-01      0
  B         2010-02-10      9
  B         2010-02-21      11
  B         2010-02-23      2

第一行有0 表示差异,因为没有更早的日期。第二行显示8,因为2010-01-01 和2010-01-09 之间的差是八天。

问题不在于计算两个datetime 对象之间的日差。我只是不确定如何添加新列。我知道,我必须先创建一个groupby(df.groupby('player')),然后再使用apply(或者可能是transform?)。但是,我被卡住了,因为为了计算差异,我需要参考应用函数中的 上一行,如果可能的话,我不知道该怎么做。

非常感谢。

更新: 在尝试了以下两种建议的解决方案后,我发现它们不适用于我的代码。经过一番头疼后,我发现我的数据有重复的索引。因此,在我发现我有重复的索引后,一个简单的df.reset_index() 解决了我的问题并且建议的解决方案有效。由于两种解决方案都有效,但我只能将一个标记为正确,因此我将选择更简洁/更短的解决方案。不过,谢谢你们!

【问题讨论】:

    标签: python pandas dataframe apply


    【解决方案1】:

    你可以简单地写:

    df['difference'] = df.groupby('player')['date'].diff().fillna(0)
    

    这为新的 timedelta 列提供了正确的值:

      player       date  difference
    0      A 2010-01-01      0 days
    1      A 2010-01-09      8 days
    2      A 2010-01-11      2 days
    3      A 2010-01-15      4 days
    4      B 2010-02-01      0 days
    5      B 2010-02-10      9 days
    6      B 2010-02-21     11 days
    7      B 2010-02-23      2 days
    

    (我使用名称“difference”而不是“diff”来区分名称和方法diff。)

    【讨论】:

    • 这看起来不错,但是,我收到此错误:File "<string>", line 17, in diff / ValueError。也许我的数据有问题?我的“日期”列肯定包含日期时间对象。我只是仔细检查了。
    • @beta:这很奇怪,如果您的列是 datetime64 类型,我不确定该错误表示什么 - 您使用的是当前版本的 pandas 吗?
    • 列的类型是<type 'datetime.date'>,我用的是pandas版本0.16.1。
    • 在这种情况下,可能需要先更改类型;你可以试试df['date'] = pd.to_datetime(df['date']),然后看看这个方法是否有效。
    • 我尝试了你的建议。还是同样的错误。但是现在列的数据类型是<class 'pandas.tslib.Timestamp'>。这是想要的吗?
    【解决方案2】:

    如果您想手动实现它,另一种方法是执行以下操作

    def date_diff(df):
        df['difference'] = df['date'] - df['date'].shift()
        df['difference'].fillna(0 ,inplace = True)
        return df
    
    In [30]:
    df_final = df.groupby(df['player']).apply(date_diff)
    df_final
    Out[30]:
    player  date    difference
    A   2010-01-01  0 days
    A   2010-01-09  8 days
    A   2010-01-11  2 days
    A   2010-01-15  4 days
    B   2010-02-01  0 days
    B   2010-02-10  9 days
    B   2010-02-21  11 days
    B   2010-02-23  2 days
    

    【讨论】:

    • 我收到raise ValueError("cannot reindex from a duplicate axis")。你知道为什么吗?我刚刚查看了date_diff(df) 中返回的df,它看起来不错。我想索引有一些问题......但我无法解决它..
    • 我建议您将该函数应用于数据子集,例如第一行 100 如果有效,然后增加子集,直到您收到错误并知道数据集中的哪些行导致问题
    • 感谢您的提示。我刚试过df.head(2).groupby(df['player']).apply(date_diff),它也不起作用。什么是重复轴?
    • 是的。我真的已经很绝望了。这应该很容易,但我无法弄清楚我的问题。
    • 你能发布完整的错误信息和堆栈跟踪
    【解决方案3】:

    shift()是个不错的功能,但是如果你需要避免数据重复,我建议如下方法。

    def date_diff(row):
        index = df.index.get_loc(row.name)
        if index == 0:
            return np.nan
        prev_row = df.iloc[index - 1]
        return row['date'] - prev_row['date']
    
    df['difference'] = df.apply(date_diff, axis=1)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-23
      • 2017-04-11
      • 2016-10-17
      • 2020-03-01
      • 1970-01-01
      • 2021-01-06
      • 2021-01-05
      相关资源
      最近更新 更多