【问题标题】:Pandas: issue with unique groupby and datetime熊猫:唯一的 groupby 和 datetime 问题
【发布时间】:2017-01-17 06:21:14
【问题描述】:

我有一个这样的 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

如何维护日期的格式?

【问题讨论】:

  • 问题是unique 将返回一个包含所有唯一值的数组。你想达到什么目的?这似乎是XY problem 的一个实例。
  • @root tl;dr 我实际上是在尝试将两个 DataFrame 连接在一起,df1 和 df2。 df1 有一个时间戳列,df2 有一个时间戳。但是,在 df1 中,每个索引都有多个实例,而在 df2 中,每个索引只有一个实例。因此,加入后,我留下了一个 DataFrame,其中每个索引都有 df2 中时间戳列的重复值。这就是我采用 unique() 的原因,因为我只想要唯一的时间戳。我正在对 id 进行分组,因为我想要每个 id 的所有时间戳。然后对于每个时间戳,我都在应用这个函数。但我很困惑为什么日期时间格式会发生变化。
  • 你能发布一个可重现的数据集(有重复)和所需的数据集吗?

标签: datetime pandas


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    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]
    

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-21
        • 2018-07-19
        • 1970-01-01
        • 2020-01-16
        • 2021-06-16
        • 2013-10-24
        • 2013-06-06
        • 2019-01-18
        相关资源
        最近更新 更多