【问题标题】:computing datetime difference among consecutive rows in groupby DataFrame计算groupby DataFrame中连续行之间的日期时间差
【发布时间】:2019-08-19 11:33:18
【问题描述】:

我遇到了熊猫问题。

我有一个如下所示的数据框:

name     date
Mark     2018-01-01
Anne     2018-01-01
Anne     2018-02-01
Anne     2018-04-01
Anne     2018-09-01
Anne     2019-01-01    
John     2018-02-01
John     2018-06-01
John     2019-02-01
Ethan    2018-03-01

我需要计算一个额外的列,称为months,它包含每个连续行之间的月数,名称相同。这是为了计算一个名称的出现与 DataFrame 中的下一个名称之间已经过去了多少个月。计算必须按名称分组,因为我只想知道一个用户连续出现之间的月数,而不是不同名称。

这种情况下的预期输出是:

name     date          months
Mark     2018-01-01    0
Anne     2018-01-01    0
Anne     2018-02-01    1
Anne     2018-04-01    2
Anne     2018-09-01    5
Anne     2019-01-01    4
John     2018-02-01    0
John     2018-06-01    4
John     2019-02-01    8
Ethan    2018-03-01    0

任何有关计算months 列的最有效方法的提示都将受到高度赞赏。

请注意,日期始终是每月的第一天,这使得计算更加容易。

【问题讨论】:

  • 不,看看我正在寻找的输出数据框。它是相似的,但是我在这里想要的计算是不同的。你给了我另一个的正确答案,也许你可以帮助得到这个答案?提前谢谢!

标签: python pandas


【解决方案1】:

通过1 month timedelta 使用GroupBy.diffdivide

df['months'] = df.groupby('name')['date'].diff().div(pd.Timedelta(days=30.44), fill_value=0).round().astype(int)

输出

    name       date  months
0   Mark 2018-01-01       0
1   Anne 2018-01-01       0
2   Anne 2018-02-01       1
3   Anne 2018-04-01       2
4   Anne 2018-09-01       5
5   Anne 2019-01-01       4
6   John 2018-02-01       0
7   John 2018-06-01       4
8   John 2019-02-01       8
9  Ethan 2018-03-01       0

【讨论】:

  • 这似乎有效!我收到了这个警告:不推荐将整数传递给 fillna,将在未来版本中引发 TypeError。要保留旧行为,请改为传递 pd.Timedelta(seconds=n)。
  • 是的,我们可以改用pd.Timedelta(days=30) 来解决这个问题。或者,如果您想非常准确:pd.Timedelta(days=30.4)。刚查了一下。最准确的版本是:pd.Timedelta(days=30.4368499)
【解决方案2】:

将值转换为months,然后通过DataFrameGroupBy.diff获得差异:

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

a = df['date'].dt.year * 12 + df['date'].dt.month - 1
df['months'] = a.groupby(df['name']).diff().fillna(0).astype(int)
print (df)
    name       date  months
0   Mark 2018-01-01       0
1   Anne 2018-01-01       0
2   Anne 2018-02-01       1
3   Anne 2018-04-01       2
4   Anne 2018-09-01       5
5   Anne 2019-01-01       4
6   John 2018-02-01       0
7   John 2018-06-01       4
8   John 2019-02-01       8
9  Ethan 2018-03-01       0

另一种解决方案:

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

from operator import attrgetter
df['months'] = (df.assign(month = df['date'].dt.to_period('m'))
                  .groupby('name')['month']
                  .diff()
                  .dropna()
                  .apply(attrgetter('n'))
                  .reindex(df.index, fill_value=0))

print (df)
    name       date  months
0   Mark 2018-01-01       0
1   Anne 2018-01-01       0
2   Anne 2018-02-01       1
3   Anne 2018-04-01       2
4   Anne 2018-09-01       5
5   Anne 2019-01-01       4
6   John 2018-02-01       0
7   John 2018-06-01       4
8   John 2019-02-01       8
9  Ethan 2018-03-01       0

【讨论】:

  • 这会不会太慢了?不过谢谢!
  • 哼哼大小可以变化,但现在我有27行6组。
  • @Erfan - 好的,我认为你的答案很糟糕,因为四舍五入。
  • 是的,这取决于你。
【解决方案3】:

从日期中提取第一个月份

df.date  = pd.to_datetime(df.date)
df['Month_from_date'] = pd.DatetimeIndex(df['date']).month

然后计算差异

df['months'] = df['Month_from_date'] - df['Month_from_date'].shift(1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-19
    • 2017-02-14
    • 2019-05-29
    • 2019-05-17
    • 1970-01-01
    • 1970-01-01
    • 2020-05-07
    • 2012-04-17
    相关资源
    最近更新 更多