如何使用groupby/cut将Pandas DataFrame的日期分组为自定义日期范围桶

4
我正在尝试使用 groupbycut 对日期进行自定义范围分组,但目前没有成功。从返回的错误信息来看,我想知道是不是 cut 正试图将我的日期处理为数字。
我想按照自定义日期范围对 df1['date'] 进行分组,然后对 df1['HDD'] 值求和。自定义范围在 df2 中找到:
import pandas as pd
df1 = pd.DataFrame( {'date': ['2/1/2015', '3/2/2015', '3/3/2015', '3/4/2015','4/17/2015','5/12/2015'],
                             'HDD' : ['7.5','8','5','23','11','55']})
    HDD  date
0   7.5 2/1/2015
1   8   3/2/2015
2   5   3/3/2015
3   23  3/4/2015
4   11  4/17/2015
5   55  5/12/2015

df2有自定义日期范围:

df2 = pd.DataFrame( {'Period': ['One','Two','Three','Four'],
                     'Start Dates': ['1/1/2015','2/15/2015','3/14/2015','4/14/2015'],
                     'End Dates' : ['2/14/2015','3/13/2015','4/13/2015','5/10/2015']})

    Period  Start Dates End Dates
0   One     1/1/2015    2/14/2015
1   Two     2/15/2015   3/13/2015
2   Three   3/14/2015   4/13/2015
3   Four    4/14/2015   5/10/2015

我希望将df1按照自定义日期范围分组,并对每个时期的HDD值进行聚合。输出应类似于以下内容:
   Period    HDD
0  One       7.5
1  Two       36
2  Three     0
3  Four      11

以下是我尝试使用自定义分组的一个例子:

df3 = df1.groupby(pd.cut(df1['date'], df2['Start Dates'])).agg({'HDD': sum})

...这里是我遇到的错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-103-55ea779bcd73> in <module>()
----> 1 df3 = df1.groupby(pd.cut(df1['date'], df2['Start Dates'])).agg({'HDD': sum})

/opt/conda/lib/python3.5/site-packages/pandas/tools/tile.py in cut(x, bins, right, labels, retbins, precision, include_lowest)
    112     else:
    113         bins = np.asarray(bins)
--> 114         if (np.diff(bins) < 0).any():
    115             raise ValueError('bins must increase monotonically.')
    116 

/opt/conda/lib/python3.5/site-packages/numpy/lib/function_base.py in diff(a, n, axis)
   1576         return diff(a[slice1]-a[slice2], n-1, axis=axis)
   1577     else:
-> 1578         return a[slice1]-a[slice2]
   1579 
   1580 

TypeError: unsupported operand type(s) for -: 'str' and 'str'
  • 是否cut试图将我的日期范围处理为数字?
  • 我是否需要显式地将我的日期转换为datetime对象(尝试过这样做,但可能不正确)?

感谢提供任何建议!


你应该先在df1中创建'Period',然后计算按组汇总的摘要。 - pe-perry
@kitman0804 - 这是一个我试图实现的最小代码示例。在我的实际问题中,数据(在我的问题中表示为df1df2)是从外部源导入的,因此我没有创建它们不同的选项。除非我误解了你的建议。 - Adrien
我是指首先在df1中创建'Period'变量,就像这里的人们所做的那样(https://dev59.com/IFYN5IYBdhLWcg3w_84w),然后进行聚合。 - pe-perry
@kitman0804 好的,我现在明白你的意思了。我会看一下那篇帖子。乍一看,它似乎可以工作。我会回报的。谢谢! - Adrien
可能是重复问题:https://dev59.com/fFcP5IYBdhLWcg3w_u8U - spadarian
@kitman0804 - 我切换到 Pandas v20.3 后,你在这里提到的解决方案 [here] (https://dev59.com/IFYN5IYBdhLWcg3w_84w) 工作得很好。我最初使用的是 Pandas 19.2。 - Adrien
1个回答

4
这将会生效,如果你将所有的日期从字符串类型转换为日期时间类型。
df1['date'] = pd.to_datetime(df1['date'])

df2['End Dates'] = pd.to_datetime(df2['End Dates'])

df2['Start Dates'] = pd.to_datetime(df2['Start Dates'])

df1['HDD'] = df1['HDD'].astype(float)

df1.groupby(pd.cut(df1['date'], df2['Start Dates'])).agg({'HDD': sum})

输出:

                           HDD
date                          
(2015-01-01, 2015-02-15]   7.5
(2015-02-15, 2015-03-14]  36.0
(2015-03-14, 2015-04-14]   NaN

添加标签:

df1.groupby(pd.cut(df1['date'], df2['Start Dates'], labels=df2.iloc[:-1,1])).agg({'HDD': sum})

输出:

        HDD
date       
One     7.5
Two    36.0
Three   NaN

我完全复制了你的代码并尝试运行它,但是出现了以下错误:TypeError: Cannot cast ufunc less input from dtype('<m8[ns]') to dtype('<m8') with casting rule 'same_kind'。不确定<m8是从哪里来的。我明确检查了每个日期列的dtype,它们都显示为datetime64[ns]。我正在iPython笔记本中运行Pandas 0.19.2。 - Adrien
我切换到另一个安装了Pandas v20.3的iPython笔记本实例,这个解决方案完美地工作了。谢谢!看来我在stackoverflow上尝试过的许多解决方案都无法按照发布的方式工作,因为我一直使用coursera课程中的旧版本Pandas(v19.2)。 - Adrien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接