将 pandas 数据帧行移动到最近的时间步长

Posted

技术标签:

【中文标题】将 pandas 数据帧行移动到最近的时间步长【英文标题】:shift pandas dataframe rows to the nearest timestep 【发布时间】:2021-11-09 10:09:07 【问题描述】:

背景

我有一个包含数百个数千个值的大型数据框。数据框的头部如下所示

df = pd.DataFrame([np.nan, 1100, 1400, np.nan, 14000],
                   index=pd.to_datetime(["2011-05-25 10:00:00",
                                         "2011-05-25 16:40:00",
                                         "2011-05-25 17:06:00",
                                         "2011-05-25 17:10:00",
                                         "2011-05-25 17:24:00"])

                           0
2011-05-25 10:00:00      NaN
2011-05-25 16:40:00   1100.0
2011-05-25 17:06:00   1400.0
2011-05-25 17:10:00      NaN
2011-05-25 17:24:00  14000.0

我想要什么

这些值并不总是以 6 分钟的时间步长记录。我想将未在 6 分钟时间步长记录的值移动到最近的 6 分钟步长。我希望新的数据框如下所示

n_df = pd.DataFrame([np.nan, 1100, 1400, np.nan, 14000],
                   index=pd.to_datetime(["2011-05-25 10:00:00",
                                         "2011-05-25 16:42:00",
                                         "2011-05-25 17:06:00",
                                         "2011-05-25 17:12:00",
                                         "2011-05-25 17:24:00"])
                   )

                           0
2011-05-25 10:00:00      NaN
2011-05-25 16:42:00   1100.0
2011-05-25 17:06:00   1400.0
2011-05-25 17:12:00      NaN
2011-05-25 17:24:00  14000.0

对我来说重要的是,n_df 中的所有值都应为 6 分钟时间步长,因此属性 n_df.index.freq 不得为 None

我怎样才能做到这一点。

到目前为止,我正在使用 for 循环通过迭代 df 并找到最近的 6 分钟步并将值移动/复制到该步,但如果 df 大于 1000,这将非常慢.

我尝试过的


    index = pd.date_range(df.index[0], end=df.index[-1], freq="6min")
    pydatetime_index = index.to_pydatetime()
    n_df = pd.DataFrame(columns=df.columns, index=index)

    for _idx, i in enumerate(df.index):
        nearest_neighbor = np.abs(pydatetime_index - i.to_pydatetime())
        idx = np.argmin(nearest_neighbor)
        val = df.loc[i]
        n_df.iloc[idx] = val

【问题讨论】:

而不是 argmin,它需要遍历整个 index,您只能遍历 -3 min、-2 min ... +2 min、+3 min 的偏移量。这应该会提高你的速度。如果您不介意每隔 6 分钟创建新的 nan 条目,您应该像下面@jazrael 的回答那样重新索引或重新采样。 【参考方案1】:

您可以使用merge_asofnearest 并指定tolerance 参数:

index = pd.date_range(df.index[0], end=df.index[-1], freq="6min")
df1 = pd.DataFrame(index=index)

df2 = pd.merge_asof(df1, 
                    df, 
                    left_index=True, 
                    right_index=True, 
                    direction='nearest', 
                    tolerance=pd.Timedelta('3Min'))
print (df2)
                           0
2011-05-25 10:00:00      NaN
2011-05-25 10:06:00      NaN
2011-05-25 10:12:00      NaN
2011-05-25 10:18:00      NaN
2011-05-25 10:24:00      NaN
                     ...
2011-05-25 17:00:00      NaN
2011-05-25 17:06:00   1400.0
2011-05-25 17:12:00      NaN
2011-05-25 17:18:00      NaN
2011-05-25 17:24:00  14000.0

[75 rows x 1 columns]

或与DataFrame.reindex类似:

df2 = df.reindex(index, method='nearest', tolerance=pd.Timedelta('3Min'))
print (df2)
                           0
2011-05-25 10:00:00      NaN
2011-05-25 10:06:00      NaN
2011-05-25 10:12:00      NaN
2011-05-25 10:18:00      NaN
2011-05-25 10:24:00      NaN
                     ...
2011-05-25 17:00:00      NaN
2011-05-25 17:06:00   1400.0
2011-05-25 17:12:00      NaN
2011-05-25 17:18:00      NaN
2011-05-25 17:24:00  14000.0

[75 rows x 1 columns]

或者:

df2 = df.resample('6Min').first()
print (df2)
                           0
2011-05-25 10:00:00      NaN
2011-05-25 10:06:00      NaN
2011-05-25 10:12:00      NaN
2011-05-25 10:18:00      NaN
2011-05-25 10:24:00      NaN
                     ...
2011-05-25 17:00:00      NaN
2011-05-25 17:06:00   1400.0
2011-05-25 17:12:00      NaN
2011-05-25 17:18:00      NaN
2011-05-25 17:24:00  14000.0

[75 rows x 1 columns]

【讨论】:

非常感谢您的回答。有没有办法在你的答案中添加插值选项。例如,我们知道 16:40:00 的值是 1100,而 17:06:00 的值是 1400。我们是否可以将插值放在 16:42? @AtherCheema - 真的很复杂,你觉得this 吗?

以上是关于将 pandas 数据帧行移动到最近的时间步长的主要内容,如果未能解决你的问题,请参考以下文章

将 CountVectorizer 和 TfidfTransformer 稀疏矩阵转换为单独的 Pandas 数据帧行

Pandas 按功能过滤数据帧行

使用Python pandas获取所有数据帧行[重复]

Pandas过滤值小于10且大于1000的数据帧行[重复]

根据字符串值列对 pandas 数据帧行进行排序

将数据从 sqlalchemy 移动到 pandas DataFrame