首页 > 解决方案 > 替换列(字符串)中的值时无法覆盖现有数据框值

问题描述

我有一个带有客户 ID 和性别的熊猫数据框。然而,在清理数据集时,我注意到一些 ID 分配了两种性别,在大多数情况下是女性或男性和未知。

df 看起来像这样:

 index   ID    gender
   0     23      M
   1     23      U
   2     55      F
   3     55      U

我的目标是找到分配了两种性别的 ID,并将 U 性别替换为非 U 性别。

为此,我在列表上使用了 for 循环,其中包含所有性别不一致的客户 ID。例如,对于 ID = 23,循环内的代码如下所示:

if all((customers.loc[customers['ID'] == 23]['gender'].str.contains('M')) | (customers.loc[customers['ID'] == 23]['gender'].str.contains('U'))):
    customers.loc[customers['ID'] == 23]['gender'] = customers.loc[customers['ID'] == 23]['gender'].replace('U', 'M')

我的问题:

  1. 不确定 for 循环和 if 语句是否最适合执行我的任务
  2. 在使用我的方法时,我无法覆盖现有的数据框。我尝试使用 replace(inplace = True),我尝试使用 .loc() 分配新的性别,但也使用链式索引。在所有情况下,我都会收到警告(使用 .loc 或链式索引时):

    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    See the caveats in the documentation: http://pandas.pydata.org/pandas- 
    docs/stable/indexing.html#indexing-view-versus-copy
    

(当使用替换(就地=真)

    C:\Users\***: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame

并且原始数据框完好无损。

我广泛地查看了 StackOverflow,但我仍然无法解决我的问题。

标签: pythonstringpandasdataframe

解决方案


对于此任务,循环将是低效的。相反,您可以使用groupby. 这是一种依赖于排序的解决方案。

请注意,升序排序NaN出现在M和下方F

res = df.copy()

res['gender'] = res.replace('U', np.nan\
                   .sort_values('gender')\
                   .groupby('ID')['gender'].transform('first')\
                   .fillna('U')\
                   .sort_values('index')

print(res)

   index  ID gender
0      0  23      M
1      1  23      M
2      2  55      F
3      3  55      F

在这种特定情况下,正如@pshep123 所提到的,因为U按字母顺序出现在之后MF您可以采用分组最小值:

res['gender'] = res.groupby('ID')['gender'].transform('min')

推荐阅读