Pandas groupby 转换中的时间戳差异
Pandas timestamp difference in groupby transform
我有一个带有整数索引、session_id、事件和 time_stamp 的数据框,如下所示:
In [41]: df = pd.DataFrame(data={'session_id': np.sort(np.random.choice(np.arange(3), 11)), 'event': np.random.choice(['A', 'B', 'C', 'D'], 11), 'time_stamp': pd.date_range
...: ('1/1/2017', periods=11, freq='S')}).reset_index(drop=True)
In [42]: df
Out[42]:
event session_id time_stamp
0 B 0 2017-01-01 00:00:00
1 C 0 2017-01-01 00:00:01
2 D 0 2017-01-01 00:00:02
3 B 1 2017-01-01 00:00:03
4 B 1 2017-01-01 00:00:04
5 D 2 2017-01-01 00:00:05
6 B 2 2017-01-01 00:00:06
7 A 2 2017-01-01 00:00:07
8 B 2 2017-01-01 00:00:08
9 B 2 2017-01-01 00:00:09
10 A 2 2017-01-01 00:00:10
我想使用 groupby
和 lambda
函数计算会话长度,但我想 return 一个与原始数据帧索引相同的系列对象,以便我可以添加它作为一列。这应该可以像这样使用 groupby.transform
,但是 return 是一个奇怪的 "cannot convert object to numpy datetime" 错误:
In [44]: df.groupby('session_id')['time_stamp'].transform(lambda x: x.max() - x.min())
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-44-c67ed1d4a90e> in <module>()
----> 1 df.groupby('session_id')['time_stamp'].transform(lambda x: x.max() - x.min())
/Users/hendele/anaconda2/lib/python2.7/site-packages/pandas/core/groupby.pyc in transform(self, func, *args, **kwargs)
2843
2844 indexer = self._get_index(name)
-> 2845 result[indexer] = res
2846
2847 result = _possibly_downcast_to_dtype(result, dtype)
ValueError: Could not convert object to NumPy datetime
我以为我用错了,但是当你使用 groupby.agg
时,它起作用了!
In [43]: df.groupby('session_id')['time_stamp'].agg(lambda x: x.max() - x.min())
Out[43]:
session_id
0 00:00:02
1 00:00:01
2 00:00:05
Name: time_stamp, dtype: timedelta64[ns]
能否请您解释一下这是否是错误,如果不是,我做错了什么?谢谢!
p.s。不想使用时间戳索引,因为我可能在实际数据中有重复的时间戳。
为什么 agg
有效但 transform
失败?
这两种行为的区别在于transform()
操作需要return一个like-indexed。为方便起见,transform
从原始系列的副本开始。然后,在对每个组进行计算之后,将复制序列的适当元素设置为等于结果。在那一点上进行类型比较,发现 timedelta
不是 cast-able 到 datetime
。 agg()
不执行此步骤,因此类型检查不会失败。
解决方法:
此分析建议解决方法。如果 transform
的结果是 datetime
,它将成功。所以要解决:
base_time = df['time_stamp'][0]
df.groupby('session_id')['time_stamp'].transform(
lambda x: x.max() - x.min() + base_time) - base_time
这是一个错误吗?
我认为这是一个错误,我打算在早上提交一个问题。我将在这里更新问题 link.
更新:
我已针对此问题提交 bug and a pull request。
我有一个带有整数索引、session_id、事件和 time_stamp 的数据框,如下所示:
In [41]: df = pd.DataFrame(data={'session_id': np.sort(np.random.choice(np.arange(3), 11)), 'event': np.random.choice(['A', 'B', 'C', 'D'], 11), 'time_stamp': pd.date_range
...: ('1/1/2017', periods=11, freq='S')}).reset_index(drop=True)
In [42]: df
Out[42]:
event session_id time_stamp
0 B 0 2017-01-01 00:00:00
1 C 0 2017-01-01 00:00:01
2 D 0 2017-01-01 00:00:02
3 B 1 2017-01-01 00:00:03
4 B 1 2017-01-01 00:00:04
5 D 2 2017-01-01 00:00:05
6 B 2 2017-01-01 00:00:06
7 A 2 2017-01-01 00:00:07
8 B 2 2017-01-01 00:00:08
9 B 2 2017-01-01 00:00:09
10 A 2 2017-01-01 00:00:10
我想使用 groupby
和 lambda
函数计算会话长度,但我想 return 一个与原始数据帧索引相同的系列对象,以便我可以添加它作为一列。这应该可以像这样使用 groupby.transform
,但是 return 是一个奇怪的 "cannot convert object to numpy datetime" 错误:
In [44]: df.groupby('session_id')['time_stamp'].transform(lambda x: x.max() - x.min())
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-44-c67ed1d4a90e> in <module>()
----> 1 df.groupby('session_id')['time_stamp'].transform(lambda x: x.max() - x.min())
/Users/hendele/anaconda2/lib/python2.7/site-packages/pandas/core/groupby.pyc in transform(self, func, *args, **kwargs)
2843
2844 indexer = self._get_index(name)
-> 2845 result[indexer] = res
2846
2847 result = _possibly_downcast_to_dtype(result, dtype)
ValueError: Could not convert object to NumPy datetime
我以为我用错了,但是当你使用 groupby.agg
时,它起作用了!
In [43]: df.groupby('session_id')['time_stamp'].agg(lambda x: x.max() - x.min())
Out[43]:
session_id
0 00:00:02
1 00:00:01
2 00:00:05
Name: time_stamp, dtype: timedelta64[ns]
能否请您解释一下这是否是错误,如果不是,我做错了什么?谢谢!
p.s。不想使用时间戳索引,因为我可能在实际数据中有重复的时间戳。
为什么 agg
有效但 transform
失败?
这两种行为的区别在于transform()
操作需要return一个like-indexed。为方便起见,transform
从原始系列的副本开始。然后,在对每个组进行计算之后,将复制序列的适当元素设置为等于结果。在那一点上进行类型比较,发现 timedelta
不是 cast-able 到 datetime
。 agg()
不执行此步骤,因此类型检查不会失败。
解决方法:
此分析建议解决方法。如果 transform
的结果是 datetime
,它将成功。所以要解决:
base_time = df['time_stamp'][0]
df.groupby('session_id')['time_stamp'].transform(
lambda x: x.max() - x.min() + base_time) - base_time
这是一个错误吗?
我认为这是一个错误,我打算在早上提交一个问题。我将在这里更新问题 link.
更新:
我已针对此问题提交 bug and a pull request。