【问题标题】:Pandas: group one column by date and count cumulated number of a specific value in another columnPandas:按日期对一列进行分组,并计算另一列中特定值的累积数量
【发布时间】:2020-07-16 08:44:20
【问题描述】:

我正在尝试根据一个日期时间列按日期对 Pandas 数据框进行分组,并在此基础上根据特定值计算另一列中特定出现的次数。假设我有这个数据框:

df = pd.DataFrame({
    "customer": [
         "A", "A", "A", "A", "A", "B", "C", "C"        
    ],
    "datetime": pd.to_datetime([
        "2020-01-01 00:00:00", "2020-01-02 00:00:00", "2020-01-02 01:00:00", "2020-01-03 00:00:00", "2020-01-04 00:00:00", "2020-01-03 00:00:00", "2020-01-03 00:00:00", "2020-01-04 00:00:00"         
    ]),
    "enabled": [
      True, True, False, True, True, True, False, True            
    ]    
})

数据框如下所示:

customer    datetime                enabled
A           2020-01-01 00:00:00     True
A           2020-01-02 00:00:00     True
A           2020-01-02 01:00:00     False
A           2020-01-03 00:00:00     True
A           2020-01-04 00:00:00     True
B           2020-01-03 00:00:00     True
C           2020-01-03 00:00:00     False
C           2020-01-04 00:00:00     True

我想在每天结束时统计启用客户的数量。如果客户已启用,它将在接下来的几天内保持启用状态,除非以后有 enabled==False 行。预期的输出是:

day           count_enabled_customers
2020-01-01    1      # A
2020-01-02    0      # A has been disabled
2020-01-03    2      # A, B
2020-01-04    3      # A, B, C

有人知道如何进行此操作吗?提前非常感谢!

【问题讨论】:

  • 对于第 2020-01-04 天,计数不应该是 2 (A,C) 吗?
  • @Sushanth 客户 B 于 '2020-01-03' 启用,之后并未禁用,因此如果有意义的话,他将在接下来的几天保持启用状态

标签: python pandas datetime


【解决方案1】:

从您的数据框开始:

import pandas as pd

df = pd.DataFrame({
    "customer": [
         "A", "A", "A", "A", "A", "B", "C", "C"        
    ],
    "datetime": pd.to_datetime([
        "2020-01-01 00:00:00", "2020-01-02 00:00:00", "2020-01-02 01:00:00", "2020-01-03 00:00:00", "2020-01-04 00:00:00", "2020-01-03 00:00:00", "2020-01-03 00:00:00", "2020-01-04 00:00:00"         
    ]),
    "enabled": [
      True, True, False, True, True, True, False, True            
    ]    
})

print(df)

Out:
  customer            datetime  enabled
0        A 2020-01-01 00:00:00     True
1        A 2020-01-02 00:00:00     True
2        A 2020-01-02 01:00:00    False
3        A 2020-01-03 00:00:00     True
4        A 2020-01-04 00:00:00     True
5        B 2020-01-03 00:00:00     True
6        C 2020-01-03 00:00:00    False
7        C 2020-01-04 00:00:00     True

使用数据透视表将客户作为列,将日期作为索引

a = df.pivot(index='datetime', columns='customer', values='enabled')
print(a)

Out:
customer                 A     B      C
datetime                               
2020-01-01 00:00:00   True   NaN    NaN
2020-01-02 00:00:00   True   NaN    NaN
2020-01-02 01:00:00  False   NaN    NaN
2020-01-03 00:00:00   True  True  False
2020-01-04 00:00:00   True   NaN   True

创建您感兴趣的日期的索引

dates = pd.date_range(df.datetime.min().date(), df.datetime.max().date() + pd.offsets.Day(1), freq='D') - pd.offsets.Second(1)
print(dates)

Out:
DatetimeIndex(['2019-12-31 23:59:59', '2020-01-01 23:59:59',
               '2020-01-02 23:59:59', '2020-01-03 23:59:59',
               '2020-01-04 23:59:59'],
              dtype='datetime64[ns]', freq='D')

将您感兴趣的日期添加到索引中并对其进行排序,以便我们可以在下一步中填写

a = a.reindex(a.index.union(dates)).sort_index()
print(a)

Out:
customer                 A     B      C
2019-12-31 23:59:59    NaN   NaN    NaN
2020-01-01 00:00:00   True   NaN    NaN
2020-01-01 23:59:59    NaN   NaN    NaN
2020-01-02 00:00:00   True   NaN    NaN
2020-01-02 01:00:00  False   NaN    NaN
2020-01-02 23:59:59    NaN   NaN    NaN
2020-01-03 00:00:00   True  True  False
2020-01-03 23:59:59    NaN   NaN    NaN
2020-01-04 00:00:00   True   NaN   True
2020-01-04 23:59:59    NaN   NaN    NaN

将启用状态的最后一个值向前填充到未来的日期

a = a.ffill()
print(a)

Out: 
customer                 A     B      C
2019-12-31 23:59:59    NaN   NaN    NaN
2020-01-01 00:00:00   True   NaN    NaN
2020-01-01 23:59:59   True   NaN    NaN
2020-01-02 00:00:00   True   NaN    NaN
2020-01-02 01:00:00  False   NaN    NaN
2020-01-02 23:59:59  False   NaN    NaN
2020-01-03 00:00:00   True  True  False
2020-01-03 23:59:59   True  True  False
2020-01-04 00:00:00   True  True   True
2020-01-04 23:59:59   True  True   True

代表每天结束的时间戳的列总和

a.loc[dates].sum(axis=1)
print(a)

Out:
2019-12-31 23:59:59    0.0
2020-01-01 23:59:59    1.0
2020-01-02 23:59:59    0.0
2020-01-03 23:59:59    2.0
2020-01-04 23:59:59    3.0
Freq: D, dtype: float64

【讨论】:

  • @davidfdez @jamesschofield df.set_index(['datetime', 'customer'])['enabled'].unstack().ffill().resample('D').last().sum(axis=1) 一站式服务。
  • @ScottBoston,我认为总体上是一个改进的答案。虽然我仍然会保留枢轴,因为它使代码比df.set_index(['datetime', 'customer'])['enabled'].unstack()imo 更明确
  • 实际上枢轴不适用于重新采样,所以我会说这是最好的答案。赞成
  • 结合这两个建议,也可以这样做:df.pivot_table(index='datetime', columns='customer', values="enabled").ffill().resample('D').last().sum(axis=1)。这两个想法都很棒,谢谢大家!
猜你喜欢
  • 2021-01-14
  • 2021-10-30
  • 1970-01-01
  • 2020-08-21
  • 2021-01-15
  • 2017-02-22
  • 2021-07-13
  • 2021-02-22
  • 1970-01-01
相关资源
最近更新 更多