我在熊猫中有一个数据框,其中包含客户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')
我的问题:
使用我的方法时,我无法覆盖现有数据框。我尝试使用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
(在使用replace(inplace = True时)
C:\Users\***: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
并且原始数据框是完整的。
我对StackOverflow进行了广泛的研究,但仍然无法解决我的问题。
答案 0 :(得分:1)
对于此任务,循环将效率很低。相反,您可以使用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
按字母顺序显示在M
和F
之后,因此您可以按组取最小值:
res['gender'] = res.groupby('ID')['gender'].transform('min')