在pandas中重新采样布尔值。

3

我遇到了一个有关在 pandas 中重新采样布尔值的特殊属性。这里是一些时间序列数据:

import pandas as pd
import numpy as np

dr = pd.date_range('01-01-2020 5:00', periods=10, freq='H')
df = pd.DataFrame({'Bools':[True,True,False,False,False,True,True,np.nan,np.nan,False],
                   "Nums":range(10)},
                  index=dr)

所以数据看起来像:

                     Bools  Nums
2020-01-01 05:00:00   True     0
2020-01-01 06:00:00   True     1
2020-01-01 07:00:00  False     2
2020-01-01 08:00:00  False     3
2020-01-01 09:00:00  False     4
2020-01-01 10:00:00   True     5
2020-01-01 11:00:00   True     6
2020-01-01 12:00:00    NaN     7
2020-01-01 13:00:00    NaN     8
2020-01-01 14:00:00  False     9

我本以为在重新取样时可以对布尔列进行简单的操作(比如求和),但是(实际上)这会失败:

>>> df.resample('5H').sum()

                    Nums
2020-01-01 05:00:00    10
2020-01-01 10:00:00    35

“Bools” 列已被删除。 我的印象是因为该列的 dtypeobject 类型。 更改类型可解决此问题:

>>> r = df.resample('5H')
>>> copy = df.copy() #just doing this to preserve df for the example
>>> copy['Bools'] = copy['Bools'].astype(float)
>>> copy.resample('5H').sum()

                     Bools  Nums
2020-01-01 05:00:00    2.0    10
2020-01-01 10:00:00    2.0    35

但是(奇怪的是)您仍然可以通过对重新采样对象进行索引来对布尔值求和,而不改变 dtype

>>> r = df.resample('5H')
>>> r['Bools'].sum()

2020-01-01 05:00:00    2
2020-01-01 10:00:00    2
Freq: 5H, Name: Bools, dtype: int64

如果仅有的列是布尔值,你仍然可以重新采样(尽管该列仍为object类型):

>>> df.drop(['Nums'],axis=1).resample('5H').sum()

                    Bools
2020-01-01 05:00:00      2
2020-01-01 10:00:00      2

什么使得后两个示例可行?我可以看到它们可能更加明确("请,我真的想要重新采样这一列!"),但我不明白为什么原始的resample函数不能执行该操作,如果可以做到的话。

我发现在1.3.5版本中,pandas的groupby.resample.agg('last')会将布尔值变成浮点数。 - leeprevost
2个回答

1
好的,追踪表明:
df.resample('5H')['Bools'].sum == Groupby.sum (in pd.core.groupby.generic.SeriesGroupBy)

df.resample('5H').sum == sum (in pandas.core.resample.DatetimeIndexResampler)

跟踪groupby.py中的groupby_function,可以发现它等价于r.agg(lambda x: np.sum(x, axis=r.axis)),其中r = df.resample('5H'),输出结果为:

                     Bools  Nums  Nums2
2020-01-01 05:00:00      2    10     10
2020-01-01 10:00:00      2    35     35

实际上,它应该是 r = df.resample('5H')['Bool'](仅适用于上述情况)

resample.py中跟踪_downsample函数,发现它等同于:df.groupby(r.grouper, axis=r.axis).agg(np.sum),其输出为:

                     Nums  Nums2
2020-01-01 05:00:00    10     10
2020-01-01 10:00:00    35     35

有趣!我猜这些确实归结为略微不同的事情,感谢你找到了它。 - Tom
是的,我担心这种区别只是纯粹的同义反复(它仍然感觉像是!)- 但是,lambda 强制对每个列单独进行加法,而另一个版本则不需要(.agg(np.sum, axis=0) 却需要)。 - Partha Mandal

0

df.resample('5H').sum()Bools 列上无法正常工作,因为该列具有混合数据类型,在 pandas 中是 object。在调用 resamplegroupby 上的 sum() 时,object 类型的列将被忽略。


是的,但我更想知道为什么您可以执行 df.resample('5H')['Bools'].sum()df.drop(['Nums'],axis=1).resample('5H').sum()。在这些情况下,数据仍然是类型 object,对吧? - Tom
2
可能有一个标记可以检查是否所有列的类型都是“object”。如果是这样,sum将强制应用于所有列,这也适用于list类型。 因此,df.astype('object').resample('5H').sum()也会起作用。 - Quang Hoang
我不知道那会起作用,这也解释了为什么“drop”版本能够工作。感谢分享。 - Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接