问题
如何根据现有的前一行(商品的预测)与另一列中关联的现有值(商品的实际值)之间的关系来填充 pandas 数据框的缺失值。
详细信息| ||我有一个包含 10 列和 40 行的 pandas 数据框。这些列
直至
Date, Actual, time_from_actual_1, time_from_actual_2, time_from_actual_3...
time_from_actual_8
列包含商品的实际值,并在
Actual
列中具有每小时时间戳。
Date
列是对同一商品的及时预测。这些每天生成一次,因此预先存在的值为
time_from_actual
和
Index 0
因此,每天有 23 个缺失观测值。
Index 1
输入数据框
我想以非常具体的方式填充这些缺失值。我希望索引 1 到 24 处的“time_from_actual”值在不同时间步长和实际值之间的差异方面遵循与第一列相同的模式。
输出数据帧
我已经成功做到了这与 a
,但我非常希望看到更优雅的方法的建议。下面您将找到包含示例数据、代码和输出的完整尝试。感谢您的任何建议!
nested for loop
代码
Code
# imports
import pandas as pd
import numpy as np
# Random seed
np.random.seed(42)
# Sample data
data = {
'Date': pd.date_range(start='2023-01-01', periods=40, freq='H'),
'Actual': [100, 99.72, 101.02, 104.06, 103.60, 103.13, 106.29, 107.82, 106.88, 107.97,
107.04, 106.11, 106.59, 102.77, 99.32, 98.19, 96.17, 96.80, 94.98, 92.15,
95.09, 94.63, 94.77, 91.92, 90.83, 91.05, 88.75, 89.50, 88.30, 87.72,
86.51, 90.22, 90.19, 88.08, 89.72, 87.28, 87.70, 83.78, 81.12, 131.52],
'time_from_actual_1': [97] + [np.nan]*23 + [90] + [np.nan]*15,
'time_from_actual_2': [99] + [np.nan]*23 + [89] + [np.nan]*15,
'time_from_actual_3': [98] + [np.nan]*23 + [88] + [np.nan]*15,
'time_from_actual_4': [97] + [np.nan]*23 + [87] + [np.nan]*15,
'time_from_actual_5': [96] + [np.nan]*23 + [86] + [np.nan]*15,
'time_from_actual_6': [95] + [np.nan]*23 + [85] + [np.nan]*15,
'time_from_actual_7': [94] + [np.nan]*23 + [84] + [np.nan]*15,
'time_from_actual_8': [93] + [np.nan]*23 + [83] + [np.nan]*15,
}
# dataframe
df = pd.DataFrame(data)
# copy of the dataframe to reference original values only
original_df = df.copy()
# Fill missing values for columns starting with "time_from_actual"
time_cols = [col for col in df.columns if col.startswith('time_from_actual')]
for col in time_cols:
for i in range(1, len(df)):
if pd.isnull(df.loc[i, col]):
j = i
while j < len(df) and pd.isnull(original_df.loc[j, col]):
previous_actual = df.loc[j - 1, 'Actual']
previous_time = df.loc[j - 1, col]
current_actual = df.loc[j, 'Actual']
difference = previous_time - previous_actual
df.loc[j, col] = current_actual + difference
j += 1
可以通过利用 pandas 的矢量化运算和索引功能来简化此代码。这是一个更优雅的解决方案:
import pandas as pd
import numpy as np
# Sample data (same as yours)
data = {
'Date': pd.date_range(start='2023-01-01', periods=40, freq='H'),
'Actual': [100, 99.72, 101.02, 104.06, 103.60, 103.13, 106.29, 107.82, 106.88, 107.97,
107.04, 106.11, 106.59, 102.77, 99.32, 98.19, 96.17, 96.80, 94.98, 92.15,
95.09, 94.63, 94.77, 91.92, 90.83, 91.05, 88.75, 89.50, 88.30, 87.72,
86.51, 90.22, 90.19, 88.08, 89.72, 87.28, 87.70, 83.78, 81.12, 131.52],
'time_from_actual_1': [97] + [np.nan]*23 + [90] + [np.nan]*15,
'time_from_actual_2': [99] + [np.nan]*23 + [89] + [np.nan]*15,
'time_from_actual_3': [98] + [np.nan]*23 + [88] + [np.nan]*15,
'time_from_actual_4': [97] + [np.nan]*23 + [87] + [np.nan]*15,
'time_from_actual_5': [96] + [np.nan]*23 + [86] + [np.nan]*15,
'time_from_actual_6': [95] + [np.nan]*23 + [85] + [np.nan]*15,
'time_from_actual_7': [94] + [np.nan]*23 + [84] + [np.nan]*15,
'time_from_actual_8': [93] + [np.nan]*23 + [83] + [np.nan]*15,
}
df = pd.DataFrame(data)
# 获取以"time_from_actual"开头的列名
time_cols = [col for col in df.columns if col.startswith('time_from_actual')]
for col in time_cols:
# 计算第一个非 NaN 值与其对应“实际”值之间的差值
difference = df[col].first_valid_index() - df['Actual'].iloc[0]
# 使用 forward fill 和累积差值来填充 NaN 值
df[col] = df[col].ffill() + (df['Actual'] - df['Actual'].ffill()).cumsum() + difference
此代码执行以下操作:
- 计算差值: 对于每个“time_from_actual”列,它都会识别第一个非 NaN 值,并计算该值与“Actual”列中第一个值的差值。此差值表示该特定时间步长的模式。
-
前向填充和累积差值:
它使用
ffill()
(前向填充)来填充每个组中的第一个非 NaN 值。然后,它会计算“Actual”列中的更改(使用diff()
)并使用cumsum()
(累积求和)对其进行累积。这将创建一组反映“Actual”列中更改的偏移量。 - 应用偏移量: 最后,它会将计算的差值添加到累积偏移量中。这可以确保填充值遵循原始模式,即使“Actual”列中的值有波动。
此方法利用了 pandas 内置函数的矢量化性质,使其比使用循环效率更高。它还更简洁易懂。
标签:python,pandas,missing-data From: 78776354