【问题标题】:Create a new column in a pandas dataframe based on values found on a previous row根据在前一行找到的值在 pandas 数据框中创建一个新列
【发布时间】:2019-04-16 15:08:58
【问题描述】:

我想根据在前一行中找到的值在 pandas 数据框中创建一个新列。

具体来说,我想添加一列,其中在实际行中找到的日期与在前一行中找到的最后一个日期之间的差异(以天为单位)具有相同的 userId 和金额 > 0。

我有这个:

+--------+------------+-----------+
| UserId |    Date    |    Amount |
+--------+------------+-----------+
|      1 | 2017-01-01 |         0 |
|      1 | 2017-01-03 |        10 |
|      2 | 2017-01-04 |        20 |
|      2 | 2017-01-07 |        15 |
|      1 | 2017-01-09 |         7 |
+--------+------------+-----------+

我想要这个

+--------+------------+-----------+-------------+
| UserId |    Date    |    Amount |  Difference |
+--------+------------+-----------+-------------+
|      1 | 2017-01-01 |         0 |          -1 |
|      1 | 2017-01-03 |        10 |          -1 |
|      2 | 2017-01-04 |        20 |          -1 |
|      2 | 2017-01-07 |        15 |           3 |
|      1 | 2017-01-09 |         7 |           6 |
+--------+------------+-----------+-------------+

【问题讨论】:

  • 到目前为止你尝试过什么?您可以使用pd.timedeltapd.shift
  • 我试过df['difference'] = df.groupby(['UserId']).filter(lambda x: (x['Amount'] > 0).any())['Date'].diff().fillna(-1),但是这样只会修改过滤的列
  • 可能 groupby('UserID').max('Date') 获取每个 ID 的最后一个日期值,然后执行 timedelta 将该值传递回原始数据帧

标签: python pandas


【解决方案1】:

将您的方法考虑在内的另一种方式:

首先使用 pandas 函数 to_datetime 将您的 Date 列转换为日期时间。

df['Date'] = pd.to_datetime(df['Date'])

现在使用 groupby 以天为单位计算差异,这将显示差异,其余值将作为 NaN 得到

df['Difference'] = df[df['Amount'] > 0].groupby(['UserId'])['Date'].diff().dt.days

df
   UserId       Date  Amount  Difference
0       1 2017-01-01       0         NaN
1       1 2017-01-03      10         NaN
2       2 2017-01-04      20         NaN
3       2 2017-01-07      15         3.0
4       2 2017-01-09       7         2.0

现在,最后在 DataFrames Difference 列中填写所有 NaN's-1

df['Difference'] = df['Difference'].fillna("-1")
# df = df.fillna("-1") <-- this do the Job but in case you have NaNs in other location in df it will also replace them as `-1`

结果:

df
   UserId       Date  Amount Difference
0       1 2017-01-01       0         -1
1       1 2017-01-03      10         -1
2       2 2017-01-04      20         -1
3       2 2017-01-07      15          3
4       2 2017-01-09       7          2

【讨论】:

  • 还是有问题,这种方式不会取最后一个条目,其实你例子的最后一个userid已经改成2但应该是1
【解决方案2】:

你真的很亲近;我只是稍微修改了你的代码。

"""
UserId     Date        Amount 
1  2017-01-01          0 
1  2017-01-03         10 
2  2017-01-04         20 
2  2017-01-07         15 
1  2017-01-09          7 
"""
import pandas as pd
df = pd.read_clipboard(parse_dates=["Date"])

df['difference'] = df[df['Amount'] > 0].groupby(['UserId'])['Date'].diff().dt.days.fillna(-1)
df.loc[0, "difference"] = -1
df

输出:

   UserId       Date  Amount  difference
0       1 2017-01-01       0        -1.0
1       1 2017-01-03      10        -1.0
2       2 2017-01-04      20        -1.0
3       2 2017-01-07      15         3.0
4       1 2017-01-09       7         6.0

帮助来自:Python: Convert timedelta to int in a dataframe

显然,我手动更改了第一行;使用此代码时,您的 df 的其余部分如何摆脱?

【讨论】:

  • 仍然有些东西不起作用,第一个有 NaT,第二个有 -1 天,我希望两者都有 0 时差,另一个问题是我'不确定是否占用了最近的行...
  • 更新以反映您的 cmets。
  • 还是不行,不是取最后一个条目而是第一个来计算差...
  • 我不确定你的意思;你能发布一个更大的(15-20 行)样本数据集吗?
猜你喜欢
  • 2021-07-08
  • 1970-01-01
  • 2023-01-04
  • 1970-01-01
  • 1970-01-01
  • 2018-03-14
  • 1970-01-01
  • 2022-11-16
  • 2021-12-02
相关资源
最近更新 更多