【问题标题】:How to fill missing values in a column by random sampling another column by other column values如何通过其他列值随机抽样另一列来填充列中的缺失值
【发布时间】:2021-09-23 09:29:24
【问题描述】:

我在一列中有缺失值,我想通过从源分布中随机抽样来填充:

import pandas as pd
import numpy as np
source = pd.DataFrame({'age':5*[21],
                       'location':[0,0,1,1,1],
                       'x':[1,2,3,4,4]})
source

    age location    x
0   21  0   1
1   21  0   2
2   21  1   3
3   21  1   4
4   21  1   4

target = pd.DataFrame({'age':5*[21],
                       'location':[0,0,0,1,2],
                       'x':5*[np.nan]})
target
    age location    x
0   21  0   NaN
1   21  0   NaN
2   21  0   NaN
3   21  1   NaN
4   21  2   NaN

现在我需要通过从源数据帧中选择一个随机值 x 来填充目标数据帧中缺失的 x 值,该随机值与缺失的 x 具有相同的年龄和位置值并进行替换。如果源中没有与缺失值具有相同年龄和位置值的 x 值,则应将其保留为缺失值。

预期输出:

    age location    x
0   21  0   1 with probability 0.5 2 otherwise
1   21  0   1 with probability 0.5 2 otherwise
2   21  0   1 with probability 0.5 2 otherwise
3   21  1   3 with probability 0.33 4 otherwise
4   21  2   NaN

我可以遍历所有缺失的年龄和位置组合,对源数据帧进行切片,然后随机抽样,但我的数据集足够大,需要很长时间才能完成。

有没有更好的办法?

【问题讨论】:

  • 你的例子有点模棱两可,你能提供预期的输出吗?
  • 答案已编辑。

标签: python pandas dataframe missing-data


【解决方案1】:

您可以在两个 DataFrame 中创建 MultiIndex,然后在自定义函数中用 GroupBy.transform 中的另一个 DataFrame 替换 NaN 和 numpy.random.choice

source = pd.DataFrame({'age':5*[21],
                       'location':[0,0,1,1,1],
                       'x':[1,2,3,4,4]})

target = pd.DataFrame({'age':5*[21],
                       'location':[0,0,0,1,2],
                       'x':5*[np.nan]})

cols = ['age', 'location']

source1 = source.set_index(cols)['x']
target1 = target.set_index(cols)['x']

def f(x):
    try:
        a = source1.loc[x.name].to_numpy()
        m = x.isna()
        x[m] = np.random.choice(a, size=m.sum())
        return x
    except KeyError:
        return np.nan
       
       
target1 = target1.groupby(level=[0,1]).transform(f).reset_index()
print (target1)
   age  location    x
0   21         0  1.0
1   21         0  2.0
2   21         0  2.0
3   21         1  3.0
4   21         2  NaN

【讨论】:

    【解决方案2】:

    您可以创建一个普通的石斑鱼并执行merge

    cols = ['age', 'location']
    
    
    (target[cols]
           .assign(group=target.groupby(cols).cumcount())               # compute subgroup for duplicates
           .merge((# below: assigns a random row group
                   source.assign(group=source.sample(frac=1).groupby(cols, sort=False).cumcount())
                         .groupby(cols+['group'], as_index=False)       # get one row per group
                         .first()
                  ),
                  on=cols+['group'], how='left')    # merge
           #drop('group', axis=1) # column kept for clarity, uncomment to remove
    )
    

    输出:

       age  location  group         x
    0   20         0      0  0.339955
    1   20         0      1  0.700506
    2   21         0      0  0.777635
    3   22         1      0       NaN
    

    【讨论】:

    • 对不起,我在我的例子中不清楚。目标中可能有多个缺失值,且年龄和位置的值相同。
    • @ArtturiBjörk 我刚刚对此发表了评论;)但是它应该很容易适应
    • 如果您可以针对可能存在多个具有相同年龄和位置值的实例的情况调整您的答案,我将不胜感激。这正是我正在努力解决的问题:)
    • @ArtturiBjörk 我的解决方案怎么不适合你?
    • 年龄和位置的值不匹配
    猜你喜欢
    • 2017-08-09
    • 1970-01-01
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多