python - 重新采样 Pandas 数据帧而不填充缺失时间

标签 python pandas dataframe pandas-resample

重新采样数据帧可以将数据帧带到更高或更低的时间分辨率。大多数情况下,这用于降低分辨率(例如,将 1 分钟数据重新采样为每月值)。当数据集稀疏时(例如,在 2020 年 2 月未收集任何数据),那么 2020 年 2 月的行中将填充 NaN 重新采样的数据帧。问题是当数据记录很长且稀疏时有很多 NaN 行,这会使数据框不必要地大并占用大量 CPU 时间。例如,考虑这个数据框和重采样操作:

import numpy as np
import pandas as pd

freq1 = pd.date_range("20000101", periods=10, freq="S")
freq2 = pd.date_range("20200101", periods=10, freq="S")

index = np.hstack([freq1.values, freq2.values])
data = np.random.randint(0, 100, (20, 10))
cols = list("ABCDEFGHIJ")

df = pd.DataFrame(index=index, data=data, columns=cols)

# now resample to daily average
df = df.resample(rule="1D").mean()
此数据框中的大部分数据都是无用的,可以通过以下方式删除:
df.dropna(how="all", axis=0, inplace=True)
然而,这是草率的。是否有另一种方法来重新采样没有用 NaN 填充所有数据间隙的数据帧(即在上面的示例中,结果数据帧只有两行)?

最佳答案

用(我认为的)更新我的原始答案是一种改进,加上更新时间。
使用 groupby您可以通过多种方式使用 groupby而不是 resample .在一天( "1D" )重采样的情况下,您可以只使用 date DateTimeIndex 的属性(property):

df = df.groupby(df.index.date).mean()
这实际上比 resample 快为您的数据:
%%timeit
df.resample(rule='1D').mean().dropna()
# 2.08 ms ± 114 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
df.groupby(df.index.date).mean()
# 666 µs ± 15.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
更通用的方法是使用时间戳的下限来做 groupby手术:
rule = '1D'
f = df.index.floor(rule)
df.groupby(f).mean()

#                A     B     C     D     E     F     G     H     I     J
# 2000-01-01  50.5  33.5  62.7  42.4  46.7  49.2  64.0  53.3  71.0  38.0
# 2020-01-01  50.4  56.3  57.4  46.2  55.0  60.2  60.3  57.8  63.5  47.3
这也适用于更不规则的频率。这里的主要障碍是,默认情况下,地板似乎是根据某个初始日期计算的,这可能会导致奇怪的结果( see my post ):
rule = '7D'
f = df.index.floor(rule)
df.groupby(f).mean()

#                A     B     C     D     E     F     G     H     I     J
# 1999-12-30  50.5  33.5  62.7  42.4  46.7  49.2  64.0  53.3  71.0  38.0
# 2019-12-26  50.4  56.3  57.4  46.2  55.0  60.2  60.3  57.8  63.5  47.3
主要问题是重采样不是从数据中最早的时间戳开始。但是,它可以使用 this solution to the above post 修复:
# custom function for flooring relative to a start date
def floor(x, freq):
    offset = x[0].ceil(freq) - x[0]
    return (x + offset).floor(freq) - offset

rule = '7D'
f = floor(df.index, rule)
df.groupby(f).mean()

#                A     B     C     D     E     F     G     H     I     J
# 2000-01-01  50.5  33.5  62.7  42.4  46.7  49.2  64.0  53.3  71.0  38.0
# 2019-12-28  50.4  56.3  57.4  46.2  55.0  60.2  60.3  57.8  63.5  47.3

# the cycle of 7 days is now starting from 01-01-2000
请注意这里的函数 floor()pandas.Series.dt.floor() 相比相对较慢.所以如果可以的话,对我们来说最好是后者,但两者都比原来的好 resample (在你的例子中):
%%timeit
df.groupby(df.index.floor('1D')).mean()
# 1.06 ms ± 6.52 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%%timeit
df.groupby(floor(df.index, '1D')).mean()
# 1.42 ms ± 14.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

关于python - 重新采样 Pandas 数据帧而不填充缺失时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62817920/

相关文章:

python - __next__ 和 next 带参数

python - Selenium - 无法点击隐藏元素

python - 如何在数据帧上执行 pd.get_dummies(),同时保留 NA 值而不是创建 NA 列?

python - 如何在 Pandas 中按年份显示饼图

python - 有条件的 Pandas Dataframe

python - 清理 Pandas 中的数字列

python - 预取 Django 模型属性

python - 我可以在没有 GUI 的情况下使用 OS X 10.8 的语音识别/听写吗?

python - 有没有办法检查列表项是否是列表中的唯一项目?

python - reshape 数据帧以与另一个数据帧具有相同的索引