[英]Resample Pandas Dataframe Without Filling in Missing Times
对 dataframe 重新采样可以使 dataframe 的时间分辨率更高或更低。 大多数情况下,这用于 go 以降低分辨率(例如,将 1 分钟数据重新采样为每月值)。 当数据集稀疏时(例如,2020 年 2 月没有收集到数据),2020 年 2 月的行将用重新采样的 dataframe 的 NaN 填充。 问题是当数据记录很长且稀疏时,会有很多 NaN 行,这使得 dataframe 不必要地大并占用大量 CPU 时间。 例如,考虑这个 dataframe 和重采样操作:
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()
此 dataframe 中的大部分数据都是无用的,可以通过以下方式删除:
df.dropna(how="all", axis=0, inplace=True)
但是,这是草率的。 是否有另一种方法来重新采样 dataframe 不能用 NaN 填充所有数据间隙(即在上面的示例中,生成的 dataframe 只有两行)?
用(我认为)更新我的原始答案是一种改进,加上更新的时间。
groupby
有几种方法可以使用groupby
而不是resample
。 在一天( "1D"
)重采样的情况下,您可以只使用DateTimeIndex
的date
属性:
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
这也适用于更不规则的频率。 这里的主要障碍是,默认情况下,似乎地板是参考一些初始日期计算的,这可能会导致奇怪的结果( 见我的帖子):
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
主要问题是重采样不是从数据中最早的时间戳开始的。 但是,可以使用此解决方案对上述帖子进行修复:
# 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
请注意,与 pandas.Series.dt.floor() 相比, pandas.Series.dt.floor()
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.