熊猫:独特的groupby和datetime问题

时间:2017-01-16 21:53:45

标签: datetime pandas

我有一个像这样的CSV文件:

id,timestamp
1,2015-03-02
2,2015-03-03

然后我加载到这样的DataFrame中:

df = pd.read_csv('file.csv', index_col=['id'], parse_dates=['timestamp'])

然后我按ID分组,选择时间戳列,并应用函数返回时间戳 - 天

df.groupby(level='id')['timestamp'].apply(lambda x: x - pd.Timedelta('1 days'))  

结果:

id
1   2015-03-01
2   2015-03-02
Name: timestamp, dtype: datetime64[ns]

但是,当我将unique()应用于groupby对象时,时间戳会更改为意外格式。

df.groupby(level='id')['timestamp'].unique().apply(lambda x: x - pd.Timedelta('1 days'))

id
1    [2015-03-02T00:00:00.000000000]
2    [2015-03-03T00:00:00.000000000]
Name: timestamp, dtype: object

如何维护日期格式?

3 个答案:

答案 0 :(得分:2)

unique返回唯一值的序列。这就是

的结果
df.groupby(level='id')['timestamp'].unique()

是一系列列表。

相反,要删除重复项,请使用drop_duplicates

result = df.reset_index().drop_duplicates(subset=['id', 'timestamp']).set_index('id')

由于drop_duplicates要求子集成为列列表,因此上面使用reset_indexid索引级别移至列,并使用set_index移动删除重复项后返回索引。

尽可能避免使用apply。当传递自定义Python函数时,apply在普通的Python循环中调用该函数 - 因此它比矢量化操作慢。 如果您可以使用矢量化操作执行计算,则代码将运行得更快。

在这种情况下,可以更快地从整个列中一次减去1天(无论是组还是重复):

df['timestamp'] -= pd.Timedelta(days=1)

这种情况可能较慢的一种情况是,如果DataFrame很大但是由 只有一个(或几个)('id', 'timestamp')组。但总的来说,应用一个 对整列的矢量化操作将比多个函数更快 呼叫应用于较小的组。

所以,例如,

import pandas as pd
import numpy as np
Timestamp = pd.Timestamp

df = pd.DataFrame({'timestamp': [Timestamp('2015-03-02 00:00:00'), Timestamp('2015-03-02 00:00:00'), Timestamp('2015-03-03 00:00:00'), Timestamp('2015-03-03 00:00:00')]}, index=pd.Index([1, 1, 1, 2], name='id'),)
#     timestamp
# id           
# 1  2015-03-02
# 1  2015-03-02
# 1  2015-03-03
# 2  2015-03-03

df['timestamp'] -= pd.Timedelta(days=1)
result = df.reset_index().drop_duplicates(subset=['id', 'timestamp']).set_index('id')

print(result)
#     timestamp
# id           
# 1  2015-03-01
# 1  2015-03-02
# 2  2015-03-02

答案 1 :(得分:0)

groupby返回数组,这就是为什么你看到它们显示的原因。如果你想要一个具有时间戳的系列,你需要使用类似下面的apply方法来获取这些值。

grouped = df.groupby(level='id')['timestamp'].unique().apply(lambda x: x - pd.Timedelta('1 days'))

grouped.apply(lambda x: x[0])

>

id
1   2015-03-01
2   2015-03-02
Name: timestamp, dtype: datetime64[ns]

答案 2 :(得分:0)

格式正在变为列表,因为您要求的是唯一值(可能有多个值)。比方说,你可以只返回第一个:

df.groupby(level='id')['timestamp'].unique().apply(lambda x: x[0] - pd.Timedelta('1 days'))

PS。我的猜测是@ unutbu的解决方案对你来说会更好。