当 pandas 数据框为空时,填充列中最接近的值

问题描述 投票:0回答:2

假设我们有一个如下所示的 pandas 数据框

ID    Name    DateTime               Days
------------------------------------------
1    AAA     2022-06-22 10:00:05     12
2    BBB     2022-06-22 10:02:00     
3    CCC     2022-06-22 10:04:00     16
4    DDD     2022-06-22 10:05:00     
5    EEE     2022-06-22 10:05:59     18

因此需要根据日期时间用最接近的值填充“天”列,例如第 2 行最近的值位于第 1 行,因为时间差小于第 3 行。 结果应该如下表所示。 其他规则如

  1. 对于第一行,它应该是下一个可能的值
  2. 对于最后一行,它应该位于可能值之前
  3. 如果两个时间相等,则取之前的值
ID    Name    DateTime               Days
------------------------------------------
1    AAA     2022-06-22 10:00:05     12
2    BBB     2022-06-22 10:02:00     12
3    CCC     2022-06-22 10:04:00     16
4    DDD     2022-06-22 10:05:00     18
5    EEE     2022-06-22 10:05:59     18

尝试在 for 循环中执行此操作,但是由于我处理了 30k 条记录,因此花费了更多时间。还有其他方法吗? 编辑:

import pandas as pd
import numpy as np
from datetime import datetime

df = pd.DataFrame([{"Id": 1, "Name": "AAA", "DateTime":pd.Timestamp('2022-06-22 10:00:05'), "Days": 12},
                  {"Id": 2, "Name": "BBB", "DateTime":pd.Timestamp('2022-06-22 10:02:00'), "Days": None},
                  {"Id": 3, "Name": "CCC", "DateTime":pd.Timestamp('2022-06-22 10:04:00'), "Days": 16},
                  {"Id": 4, "Name": "DDD", "DateTime":pd.Timestamp('2022-06-22 10:05:00'), "Days": None},
                  {"Id": 5, "Name": "EEE", "DateTime":pd.Timestamp('2022-06-22 10:05:59'), "Days": 18}])

df['TimeUpShift'] = df['DateTime'].shift(1)
df['TimeDownShift'] = df['DateTime'].shift(-1)

此后无法继续

for 循环逻辑具有相同的作用

    if df['Days'][0] == '' or np.isnan(df['Days'][0]):
    index = df['Days'].first_valid_index()
    df['Days'][0] = df.loc[index].Days if index is not None else None
if df['Days'][len(df) - 1] == '' or np.isnan(df['Days'][len(df) - 1]):
    index = df['Days'].last_valid_index()
    df['Days'][len(df) - 1] = df.loc[index].Days if index is not None else None

for i in range(1, len(df) - 1, 1):
    if df['Days'][i] == '' or np.isnan(df['Days'][i]):
        prevrow = pd.DataFrame()
        nextrow = pd.DataFrame()
        # backward search
        for pi in range(i - 1, -1, -1):
            if not df['Days'][pi] == '' or not np.isnan(df['Days'][pi]):
                prevrow = df.loc[pi]
                break
        # forward search
        for ni in range(i + 1, len(df) + 1, 1):
            if not df['Days'][ni] == '' or not np.isnan(df['Days'][ni]):
                nextrow = df.loc[ni]
                break
        if df['DateTime'][i] - prevrow['DateTime'] <= nextrow['DateTime'] - df['DateTime'][i]:
            df['Days'][i] = prevrow['Days']
        else:
            df['Days'][i] = nextrow['Days']
python-3.x pandas dataframe
2个回答
2
投票

使用

merge_asof
,您可以合并(匹配)到最近的
DateTime

pd.merge_asof(df,df.dropna(), on='DateTime', direction='nearest', suffixes=('_x', '')) \
    [['Id', 'Name', 'DateTime', 'Days']]

   Id Name            DateTime  Days
0   1  AAA 2022-06-22 10:00:05  12.0
1   1  AAA 2022-06-22 10:02:00  12.0
2   3  CCC 2022-06-22 10:04:00  16.0
3   5  EEE 2022-06-22 10:05:00  18.0
4   5  EEE 2022-06-22 10:05:59  18.0

asof 在给定的容差范围内合并

您可以使用指定

tolerance=
TimeDelta
参数来指定合并容差:

pd.merge_asof(df,df.dropna(), on='DateTime', direction='nearest', tolerance=pd.Timedelta('1m'), suffixes=('', '_y')) \
    .drop(columns=['Days','Id_y', 'Name_y']).rename(columns={'Days_y':'Days'})

结果:

   Id Name            DateTime  Days
0   1  AAA 2022-06-22 10:00:05  12.0
1   2  BBB 2022-06-22 10:02:00   NaN
2   3  CCC 2022-06-22 10:04:00  16.0
3   4  DDD 2022-06-22 10:05:00  18.0
4   5  EEE 2022-06-22 10:05:59  18.0

上面的示例显示了最近时间的合并/匹配(如果该时间在 1 分钟内)。 有关

TimeDelta
的更多详细信息,请参阅:https://pandas.pydata.org/docs/user_guide/timedeltas.html


0
投票

您还可以使用前向填充或后向填充。 喜欢:

 df.ffill(inplace=True)

对于第一个数据,您可以选择填写,然后使用此代码。

如果您仍然希望自动化最接近的值,您可以使用插值代替:

df.interpolate(method='nearest', inplace=True)

使用插值时,请确保仅选择数字值进行填充。字符串和其他类型必须指定为:

df.update(merged_train.select_dtypes(include=['float64', 'int64']).interpolate(method='nearest'))

希望有帮助!!

© www.soinside.com 2019 - 2024. All rights reserved.