假设我们有一个如下所示的 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 行。 结果应该如下表所示。 其他规则如
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']
使用
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
您还可以使用前向填充或后向填充。 喜欢:
df.ffill(inplace=True)
对于第一个数据,您可以选择填写,然后使用此代码。
如果您仍然希望自动化最接近的值,您可以使用插值代替:
df.interpolate(method='nearest', inplace=True)
使用插值时,请确保仅选择数字值进行填充。字符串和其他类型必须指定为:
df.update(merged_train.select_dtypes(include=['float64', 'int64']).interpolate(method='nearest'))
希望有帮助!!