【问题标题】:Pandas Replace NaN values based on random sample of values conditional on another columnPandas 根据以另一列为条件的随机值样本替换 NaN 值
【发布时间】:2020-05-16 10:11:49
【问题描述】:

假设我有一个这样的数据框:

import pandas as pd
import numpy as np

np.random.seed(0)

df = {}
df['x'] = np.concatenate([np.random.uniform(0, 5, 4), np.random.uniform(5, 10, 4)])
df['y'] = np.concatenate([[0] * 4, [1] * 4])
df = pd.DataFrame(df)

df.loc[len(df) + 1] = [np.NaN, 0]
df.loc[len(df) + 1] = [np.NaN, 1]
df
Out[232]: 
           x    y
0   2.744068  0.0
1   3.575947  0.0
2   3.013817  0.0
3   2.724416  0.0
4   7.118274  1.0
5   8.229471  1.0
6   7.187936  1.0
7   9.458865  1.0
9        NaN  0.0
10       NaN  1.0

我要做的是根据x 值的随机样本填充NaN 值,该随机样本基于y 值。

例如,在 y 为 0 的第 9 行中,我想用仅从 x 值中随机采样的数字替换 NaN,其中 y 的值为 0。实际上,我会从此列表中抽样:

df[df['y'] == 0]['x'].dropna().values.tolist()
Out[233]: [2.7440675196366238, 3.5759468318620975, 3.0138168803582195, 2.724415914984484]

同样对于第 10 行,我将仅根据 y 为 1 而不是 0 的“x”值进行采样。我无法找到以编程方式执行此操作的方法(至少,在某种程度上这不是坏习惯,例如遍历数据框行)。

我咨询过Pandas: Replace NaN Using Random Sampling of Column Values,它向我展示了如何从一列中的所有值中随机抽样,但我需要随机抽样以另一列的不同值为条件。我还看到了用条件均值 (such as this) 替换 NaN 的答案,但我希望随机抽样,而不是使用均值。

【问题讨论】:

    标签: python pandas random imputation


    【解决方案1】:

    transformchoice

    为了可读性,我放弃了效率。请注意,我为每一行生成一个随机选择,但只选择我需要填写空值的数字。从理论上讲,我可以做到只为那些缺失值选择随机数。

    def f(s):
        mask = s.isna()
        return np.where(mask, np.random.choice(s[~mask], len(s)), s)
    
    df.assign(x=df.groupby('y')['x'].transform(f))
    
               x    y
    0   2.744068  0.0  # <━┓
    1   3.575947  0.0  #   ┃
    2   3.013817  0.0  #   ┃
    3   2.724416  0.0  #   ┃
    4   7.118274  1.0  #   ┃
    5   8.229471  1.0  # <━╋━┓
    6   7.187936  1.0  #   ┃ ┃
    7   9.458865  1.0  #   ┃ ┃
    9   2.744068  0.0  # <━┛ ┃
    10  8.229471  1.0  # <━━━┛
    

    略显迟钝,但只选择我们需要的数量。

    def f(s):
        out = s.to_numpy().copy()
        mask = s.isna().to_numpy()
        out[mask] = np.random.choice(out[~mask], mask.sum())
        return out
    
    df.assign(x=df.groupby('y')['x'].transform(f))
    
               x    y
    0   2.744068  0.0  # <━┓
    1   3.575947  0.0  #   ┃
    2   3.013817  0.0  #   ┃
    3   2.724416  0.0  #   ┃
    4   7.118274  1.0  # <━╋━┓
    5   8.229471  1.0  #   ┃ ┃
    6   7.187936  1.0  #   ┃ ┃
    7   9.458865  1.0  #   ┃ ┃
    9   2.744068  0.0  # <━┛ ┃
    10  7.118274  1.0  # <━━━┛
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      • 2015-12-31
      • 1970-01-01
      • 1970-01-01
      • 2018-11-29
      • 1970-01-01
      • 2018-12-05
      相关资源
      最近更新 更多