【问题标题】:Filling missing data with historical mean fast and efficiently in pandas在 pandas 中快速有效地用历史平均值填充缺失数据
【发布时间】:2019-10-20 16:48:57
【问题描述】:

我正在处理一个包含 50 万个观测值的大型面板数据集(纵向数据)。目前,我正在尝试使用每个变量直到时间 t 的平均值来填充缺失的数据(最多 30% 的观察值)。 (我不使用总体平均值填充数据的原因是为了避免因使用仅在以后某个时间点可用的数据而产生的前瞻性偏差。)

我编写了以下函数来完成这项工作,但运行速度非常慢(500k 行需要 5 小时!!)一般来说,我发现在 Pandas 中填充缺失的数据是一项繁琐的计算任务。 请告诉我您通常如何填充缺失值,以及如何使其快速运行

用直到时间“t”的平均值填充的函数:

def meanTillTimeT(x,cols):
    start = time.time()
    print('Started')
    x.reset_index(inplace=True)
    for i in cols:
        l1 =[]
        for j in range(x.shape[0]):
            if x.loc[j,i] !=0 and np.isnan(x.loc[j,i]) == False :
                l1.append(x.loc[j,i])
            elif np.isnan(x.loc[j,i])==True :
                x.loc[j,i]=np.mean(l1)      
    end = time.time()
    print("time elapsed:", end - start)
    return x

【问题讨论】:

  • 这显然会比大多数其他填充方式更加计算密集;您可能想引入我们计算平均值的最大窗口长度(然后您也可以填充块,并行化等)。此外,这种方法似乎没有标准术语,但我认为 “用前向均值填充” 是一个很好的术语。 (不叫“前向填充”,因为这只意味着“最后一次观察结转(locf)”
  • 最终,在您处理了 X% 的数据集之后,这将在数值上大致相当于用整体平均值估算(在一定的精度内),但仍然是计算密集型的。你实际需要多少准确度,你确定你真的想要这样做吗?我理解你关于偏见的观点,但人们通常不会这样做,我怀疑你真的不需要这样做。示例:您可以分块处理事物,对所有先前的块取回溯平均值,并将其同时填充到整个当前块。
  • ...最佳块大小(准确性与效率的权衡)取决于您。可能您想以对数方式增加块大小。
  • ...除了从手动迭代到cumsum() 的明显加速,如@olivaw 所示。
  • 所以我上面的 cmets 取决于你的数据分布是相当稳定的。如果您预计会出现严重的不连续性或非平稳性,则以不同的方式处理块窗口。

标签: python pandas performance na missing-data


【解决方案1】:

让我们构建一个 DataFrame 进行说明:

import pandas as pd
import numpy as np

df = pd.DataFrame({"value1": [1, 2, 1, 5, np.nan, np.nan, 8, 3],
                   "value2": [0, 8, 1, np.nan, np.nan, 8, 9, np.nan]})

这是数据框:

      value1  value2
   0     1.0     0.0
   1     2.0     8.0
   2     1.0     1.0
   3     5.0     NaN
   4     NaN     NaN
   5     NaN     8.0
   6     8.0     9.0
   7     3.0     NaN

现在,我建议首先使用pandas.DataFrame.cumsum 计算累积总和以及非NaN 值的数量,以便计算均值。之后,用这些方法填充 NaN 并将它们插入原始 DataFrame 就足够了。这两个操作都使用pandas.DataFrame.fillna,这将比 Python 循环快得多:

df_mean = df.cumsum() / (~df.isna()).cumsum()
df_mean = df_mean.fillna(method = "ffill")
df = df.fillna(value = df_mean)

结果是:

      value1  value2
   0    1.00     0.0
   1    2.00     8.0
   2    1.00     1.0
   3    5.00     3.0
   4    2.25     3.0
   5    2.25     8.0
   6    8.00     9.0
   7    3.00     5.2

【讨论】:

  • 这个解决方案听起来不错,但是纵向数据你会怎么做呢?
  • 有什么问题?您可能希望首先使用 sort_values 对 DataFrame 进行排序(例如,按日期和人员)。您可能还需要仅将计算应用于某些列,这些列很容易在 DataFrame 中选择。我有什么特别想念的吗?
  • 例如,在对数据进行排序时,nans 会出现在特定日期的底部吗?因为否则,在填充 nan 时,cumsum 将不会包含该特定日期的所有数字。
  • 你需要更具体。在您的示例代码中,我没有看到日期或面板/人员的迹象。在给定日期,您想确保对以前日期的所有数据和当前日期的所有可用日期进行平均?
  • X 是一个由多个公司在多个时间实例组成的数据框。并不是所有的公司都一直在那里。我想确保我对所有当前和过去的日期进行平均。
猜你喜欢
  • 2017-04-02
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 2021-11-28
相关资源
最近更新 更多