tnk*_*epp 9 python dataframe pandas 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()
Run Code Online (Sandbox Code Playgroud)
该数据框中的大部分数据都是无用的,可以通过以下方式删除:
df.dropna(how="all", axis=0, inplace=True)
Run Code Online (Sandbox Code Playgroud)
然而,这是草率的。是否有另一种方法来重新采样数据帧,该方法不会用 NaN 填充所有数据间隙(即在上面的示例中,生成的数据帧将只有两行)?
用(我认为的)更新我原来的答案是一种改进,加上更新时间。
\ngroupby您可以使用多种方法groupby来代替resample. 对于一天 ( "1D") 重采样,您可以仅使用date的属性DateTimeIndex:
df = df.groupby(df.index.date).mean()\nRun Code Online (Sandbox Code Playgroud)\n事实上,这比resample您的数据更快:
%%timeit\ndf.resample(rule=\'1D\').mean().dropna()\n# 2.08 ms \xc2\xb1 114 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 100 loops each)\n\n%%timeit\ndf.groupby(df.index.date).mean()\n# 666 \xc2\xb5s \xc2\xb1 15.1 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000 loops each)\nRun Code Online (Sandbox Code Playgroud)\n更通用的方法是使用时间戳的下限来执行操作groupby:
rule = \'1D\'\nf = df.index.floor(rule)\ndf.groupby(f).mean()\n\n# A B C D E F G H I J\n# 2000-01-01 50.5 33.5 62.7 42.4 46.7 49.2 64.0 53.3 71.0 38.0\n# 2020-01-01 50.4 56.3 57.4 46.2 55.0 60.2 60.3 57.8 63.5 47.3\nRun Code Online (Sandbox Code Playgroud)\n这也适用于更不规则的频率。这里的主要障碍是,默认情况下,下限似乎是参考某个初始日期计算的,这可能会导致奇怪的结果(请参阅我的帖子):
\nrule = \'7D\'\nf = df.index.floor(rule)\ndf.groupby(f).mean()\n\n# A B C D E F G H I J\n# 1999-12-30 50.5 33.5 62.7 42.4 46.7 49.2 64.0 53.3 71.0 38.0\n# 2019-12-26 50.4 56.3 57.4 46.2 55.0 60.2 60.3 57.8 63.5 47.3\nRun Code Online (Sandbox Code Playgroud)\n主要问题是重采样不会从数据中最早的时间戳开始。但是,可以使用上述帖子的解决方案来修复它:
\n# custom function for flooring relative to a start date\ndef floor(x, freq):\n offset = x[0].ceil(freq) - x[0]\n return (x + offset).floor(freq) - offset\n\nrule = \'7D\'\nf = floor(df.index, rule)\ndf.groupby(f).mean()\n\n# A B C D E F G H I J\n# 2000-01-01 50.5 33.5 62.7 42.4 46.7 49.2 64.0 53.3 71.0 38.0\n# 2019-12-28 50.4 56.3 57.4 46.2 55.0 60.2 60.3 57.8 63.5 47.3\n\n# the cycle of 7 days is now starting from 01-01-2000\nRun Code Online (Sandbox Code Playgroud)\n这里请注意,floor()与 相比,该函数相对较慢pandas.Series.dt.floor()。因此,如果可以的话,对我们来说最好是后者,但两者都比原始版本更好resample(在您的示例中):
%%timeit\ndf.groupby(df.index.floor(\'1D\')).mean()\n# 1.06 ms \xc2\xb1 6.52 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000 loops each)\n\n%%timeit\ndf.groupby(floor(df.index, \'1D\')).mean()\n# 1.42 ms \xc2\xb1 14.6 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000 loops each)\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
4433 次 |
| 最近记录: |