Pandas pd.cut() - 合并日期时间列/系列

Posted

技术标签:

【中文标题】Pandas pd.cut() - 合并日期时间列/系列【英文标题】:Pandas pd.cut() - binning datetime column / series 【发布时间】:2017-09-15 23:42:47 【问题描述】:

尝试使用 pd.cut() 做一个 bin,但它相当复杂-

一位同事向我发送了多个带有报告日期的文件,例如:

 '03-16-2017 to 03-22-2017'
 '03-23-2017 to 03-29-2017'
 '03-30-2017 to 04-05-2017'

它们都被组合成一个数据框并给出一个列名 df['Filedate'] 以便文件中的每条记录都有正确的文件日期。

最后一天是一个截止点,因此我创建了一个新列 df['Filedate_bin'],它将最后一天转换为 3/22/2017、3/29/2017、4/05/2017 作为字符串。

然后我创建了一个列表:Filedate_bin_list= df.Filedate_bin.unique()。因此,我有一个唯一的字符串截止日期列表,我想将其用作垃圾箱。

将不同的数据导入dataframe,有一列交易日期:3/28/2017、3/29/2017、3/30/2017、4/1/2017、4/2/2017等。把它们扔进垃圾箱很难,它试过了:

df['bin'] = pd.cut(df.Processed_date, Filedate_bin_list)

收到TypeError: unsupported operand type for -: 'str' and 'str'

回去尝试将 Filedate_bin 转换为 datetime,format='%m/%d/%Y' 并得到

TypeError: Cannot cast ufunc less input from dtype('<m8[ns]') to dtype ('<m8') with casting rule 'same_kind'.

有没有更好的方法将我的已处理日期放入文本箱?

我正在尝试将我处理的日期从 2017 年 3 月 27 日与“03-23-2017 到 03-29-2017”联系起来

【问题讨论】:

【参考方案1】:

更新: 从 Pandas v0.20.1 (May 5, 2017) pd.cutpd.qcut 开始支持 datetime64 和 timedelta64 dtypes(GH14714,GH14798)。

谢谢@lighthouse65 for checking this!


旧答案:

考虑这种方法:

df = pd.DataFrame(pd.date_range('2000-01-02', freq='1D', periods=15), columns=['Date'])

bins_dt = pd.date_range('2000-01-01', freq='3D', periods=6)
bins_str = bins_dt.astype(str).values

labels = ['(, ]'.format(bins_str[i-1], bins_str[i]) for i in range(1, len(bins_str))]

df['cat'] = pd.cut(df.Date.astype(np.int64)//10**9,
                   bins=bins_dt.astype(np.int64)//10**9,
                   labels=labels)

结果:

In [59]: df
Out[59]:
         Date                       cat
0  2000-01-02  (2000-01-01, 2000-01-04]
1  2000-01-03  (2000-01-01, 2000-01-04]
2  2000-01-04  (2000-01-01, 2000-01-04]
3  2000-01-05  (2000-01-04, 2000-01-07]
4  2000-01-06  (2000-01-04, 2000-01-07]
5  2000-01-07  (2000-01-04, 2000-01-07]
6  2000-01-08  (2000-01-07, 2000-01-10]
7  2000-01-09  (2000-01-07, 2000-01-10]
8  2000-01-10  (2000-01-07, 2000-01-10]
9  2000-01-11  (2000-01-10, 2000-01-13]
10 2000-01-12  (2000-01-10, 2000-01-13]
11 2000-01-13  (2000-01-10, 2000-01-13]
12 2000-01-14  (2000-01-13, 2000-01-16]
13 2000-01-15  (2000-01-13, 2000-01-16]
14 2000-01-16  (2000-01-13, 2000-01-16]

In [60]: df.dtypes
Out[60]:
Date    datetime64[ns]
cat           category
dtype: object

说明:

df.Date.astype(np.int64)//10**9 - 将 datetime 值转换为 UNIX 纪元(时间戳 - 自 1970-01-01 00:00:00 以来的秒数):

In [65]: df.Date.astype(np.int64)//10**9
Out[65]:
0     946771200
1     946857600
2     946944000
3     947030400
4     947116800
5     947203200
6     947289600
7     947376000
8     947462400
9     947548800
10    947635200
11    947721600
12    947808000
13    947894400
14    947980800
Name: Date, dtype: int64

同样适用于bins:

In [66]: bins_dt.astype(np.int64)//10**9
Out[66]: Int64Index([946684800, 946944000, 947203200, 947462400, 947721600, 947980800], dtype='int64')

标签:

In [67]: labels
Out[67]:
['(2000-01-01, 2000-01-04]',
 '(2000-01-04, 2000-01-07]',
 '(2000-01-07, 2000-01-10]',
 '(2000-01-10, 2000-01-13]',
 '(2000-01-13, 2000-01-16]']

【讨论】:

看起来我需要建立一个频率并输入多少个周期(箱)。得到一个 TypeError:不能将 datetimelike 从 [datetime64[ns]] 输入到 [uint64]。除了 pandas、numpy 和 datetime 之外的任何库? @ArthurD.Howland,试试np.int64 而不是np.uint64。不,你只需要 Pandas 和 Numpy 来完成这项任务。你的 Pandas 和 Numpy 版本是什么? np.int64 工作并重复了结果。看起来像我第一个成功的垃圾箱。可能需要一天时间才能将其转换为我的设置。使用 Python 3.5.2。看来我的垃圾箱是 7D,我可以使用我的唯一列表的长度来确定有多少垃圾箱。接近:) @MaxU 你为什么要约会?对我来说,没有.astype(np.int64)//10**9,代码工作得很好。 @Qaswed 如注 here 并包含在 Pandas v0.20.1(2017 年 5 月 5 日)的发行说明中,pd.cut 支持 datetime64 dtype。

以上是关于Pandas pd.cut() - 合并日期时间列/系列的主要内容,如果未能解决你的问题,请参考以下文章

pandas-08 pd.cut()的功能和作用

Pandas - 如何在不同格式的日期时间列上合并数据框?

pandas数据分割pd.cut使用总结

Pandas Dataframe 合并 2 列,包括条件 If 合并:如果 df_2 中的日期在 df_1 中的其他两个日期之间

如何从导入的 csv 文件中索引日期时间列 - pandas

PySpark 中 pandas.cut() 的等价物是啥?