熊猫用过滤器填充最常见的缺失值?

时间:2019-08-16 20:43:21

标签: pandas dataframe data-science

给出一个包含两列的数据框,如下所示:

| user_id | preference_id |
|---------|---------------|
| 1       | 1             |
| 1       | 2             |
| 1       | None          |
| 2       | 1             |
| 3       | 2             |
| 3       | 2             |
| 3       | None          |

如何用preference_id的最频繁值填充user_id中的缺失值?我当前的解决方案包括使用数据循环遍历所有唯一的user_id,这些preference_id至少具有一个缺失值,而preference_id的至少一个实例具有数据:

# Find all rows where preference_id is missing
pref_na = df.loc[df.preference_id.isna()]

# Find all users that have at least one missing and one not missing
# value for preference_id
users = df.loc[
  (~df.preference_id.isna()) & (df.user_id.isin(pref_na))
]

for id in users.user_id.unique():
    # Find most common preference_id for a user
    top_pref = df.loc[
        (df.user_id == id) & (~df.preference_id.isna()),
        ['preference_id']
    ]
    if top_pref.shape[0] == 0:
        continue
    top_pref = top_pref.preference_id.mode()[0]

    # Fill in missing prefs with top_pref
    df.loc[
        (df.user_id == id) & (df.preference_id.isna()),
        'preference_id'] = top_pref

是否有一种本机或矢量化方式来完成此任务?

编辑

在此示例中,@ anky_91的建议中断了:

df = pd.DataFrame({
    'user_id': [1, 1, 1, 2, 3, 3, 3],
    'preference_id': [1, 2, None, None, 2, 2, None]
})

也就是说,user_id个记录中只有一个丢失了preference_id s

编辑#2

在尝试了@ anky_91的解决方案之后,我能够通过首先过滤掉只有缺失值的用户(因此,我无法推断出缺失的preference_id的用户)来解决上述的极端情况:

# Remove edge cases
ids = df.groupby('user_id').preference_id.count()\
    .where(lambda x: x > 0).dropna().to_frame().reset_index()

# User anky_91 solution
ids.groupby('user_id').preference_id.transform(lambda x: x.mode().iat[0])

可能会有一种更高效,更优雅的方法来进行第一步,但是那样的话。最慢的部分是第二步,所以我可以接受步骤1的形式。

1 个答案:

答案 0 :(得分:2)

使用:

s=df.groupby('user_id')['preference_id'].transform(lambda x: x.mode().iat[0])
df.preference_id=df.preference_id.fillna(s)
print(df)

   user_id  preference_id
0        1            1.0
1        1            2.0
2        1            1.0
3        2            1.0
4        3            2.0
5        3            2.0
6        3            2.0

另一种方式:

m=(df.groupby('user_id')['preference_id'].apply(lambda x: x.mode(dropna=False).iat[0])
.reset_index(name='Mode'))
df.merge(m,on='user_id')

   user_id  preference_id  Mode
0        1            1.0   1.0
1        1            2.0   1.0
2        1            NaN   1.0
3        2            NaN   NaN
4        3            2.0   2.0
5        3            2.0   2.0
6        3            NaN   2.0