我在.minute
聚合的上下文中无法提取Pandas datetime对象的groupby
属性。
This post似乎涉及相同的根问题,但接受的答案只是解释了问题发生的原因(这是公平的,因为OP只是要求了解问题)。我现在正在发帖,因为我希望找到一个不依赖于明确更改数据类型的解决方案。
以下是一些示例代码:
import pandas as pd
ids = ['a','a','b','b']
dates = ['2017-01-01 01:01:00','2017-01-01 01:02:00',
'2017-03-03 01:03:00','2017-03-03 01:04:00']
dates = pd.to_datetime(pd.Series(dates))
df = pd.DataFrame({'id':ids, 'datetime':dates})
id datetime
0 a 2017-01-01 01:01:00
1 a 2017-01-01 01:02:00
2 b 2017-03-03 01:03:00
3 b 2017-03-03 01:04:00
我的目标是按id
分组,然后提取每个datetime
组中最早时间戳的分钟,作为整数值。
例如,要在所有 datetime
值之间执行此操作,这样做有效:
df.datetime.min().minute # returns 1
我想在groupby()
设置中模仿相同的功能
但是,在UDF中组合min()
和.minute
时,分钟值将被添加到标记Unix纪元开始的日期时间的末尾:
def get_earliest_minute(tstamps):
return tstamps.min().minute
df.groupby('id').agg({'datetime':get_earliest_minute})
datetime
id
a 1970-01-01 00:00:00.000000001
b 1970-01-01 00:00:00.000000003
从get_earliest_minute()
返回的类型是一个整数:
def get_earliest_minute(tstamps):
return type(tstamps.min().minute)
df.groupby('id').agg({'datetime':get_earliest_minute})
datetime
id
a <type 'int'>
b <type 'int'>
但datetime
后聚合的类型为<M8[ns]
:
df.groupby('id').agg({'datetime':get_earliest_minute}).datetime.dtype # dtype('<M8[ns]')
上面链接的帖子answer表明这是因为有目的的类型强制,它试图维护经历聚合的原始Series对象的类型。我已经环顾四周但是找不到任何解决方案,除了one comment之外建议在执行object
之前将字段类型更改为groupby()
,例如,
df.datetime = df.datetime.astype(object)
df.groupby('id').agg({'datetime':get_earliest_minute})
和another comment建议在返回之前将函数的输出转换为float
,例如,
def get_earliest_minute(tstamps):
return float(tstamps.min().minute)
这些变通办法完成了这项工作(虽然由于某种原因声明int()
不会像float()
那样逃避类型强制,但是有没有办法对datetime对象进行这些groupby
操作没有插入显式类型转换(即,推广<M8[ns]
- &gt; object
或转换int
- &gt; float
)?特别是,在多个agg()
函数应用于datetime
的情况下,某些函数依赖于日期时间属性而某些函数不依赖于日期时间属性,这将不会成功pre-groupby转换。
此外,float()
类型转换是否会覆盖内置类型强制,但int()
不会?
提前谢谢!
答案 0 :(得分:1)
我会在这个问题上坚持使用@Jeff。 agg
正在做我们想要的事情。它正在尝试保留dtype
,因为它旨在聚合特定dtype的值。 当我汇总特定dtype
的数据时,我期待同样的dtype
...
...也就是说,您可以使用apply
您的问题
def get_earliest_minute(tstamps):
return tstamps.min().minute
df.groupby('id').agg({'datetime':get_earliest_minute})
datetime
id
a 1970-01-01 00:00:00.000000001
b 1970-01-01 00:00:00.000000003
<强> 解决方法 强>
def get_earliest_minute(tstamps):
return tstamps.min().minute
df.groupby('id').datetime.apply(get_earliest_minute)
id
a 1
b 3
Name: datetime, dtype: int64