Невозможно переопределить существующие значения dataframe при замене значений в столбцах (строках)

1

У меня есть 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')

Мои проблемы:

  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
    

(при использовании replace (inplace = True)

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

и исходный блок данных не поврежден.

Я широко рассмотрел StackOverflow, но я все еще не могу решить свою проблему.

Теги:
string
pandas
dataframe

1 ответ

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')
  • 0
    Спасибо, это отлично работает. Тем не менее, у меня есть случаи, когда два пола - М и Ф. Мэйлз - это около 70% всех покупателей, а женщины - 25%. Поэтому я хотел назначить пол в таком случае на основе вероятности (с 0,7 это будет мужчина, или с 0,25 вероятностью это будет женщина). Знаете ли вы, если такое основанное на вероятности присвоение может быть выполнено без цикла for и генерирования в каждом взаимодействии новой случайной величины? Может быть, это соответствует новым вопросам?
  • 2
    Если это просто ID и пол, не могли бы вы просто сделать .groupby('ID').min().reset_index(drop = True) ? Учитывая, что «U» больше, чем «M» и «F».
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню