У меня есть dataframe в пандах с идентификаторами клиентов и их полу. Однако при очистке набора данных я заметил, что некоторые идентификаторы имеют два назначенных родителя, в большинстве случаев это женщины или мужчины и неизвестные.
Df выглядит так:
index ID gender
0 23 M
1 23 U
2 55 F
3 55 U
Моя цель состоит в том, чтобы найти идентификаторы, которые назначены двумя родителями, и заменить ген U на не-U-пол.
Для этого я использую цикл for по списку, в котором у меня есть все идентификаторы клиентов, которые имеют непоследовательные гендерные группы. Например, для 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, но я все еще не могу решить свою проблему.
Для этой задачи петля будет неэффективной. Вместо этого вы можете использовать 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')
.groupby('ID').min().reset_index(drop = True)
? Учитывая, что «U» больше, чем «M» и «F».