#python #pandas
Вопрос:
Вот некоторые данные:
test = pd.DataFrame([[np.nan,"cat","mouse", 'tiger'],
["tiger","dog","elephant", "mouse"],
["cat",np.nan,"giraffe", "cat"],
[np.nan,np.nan,"ant", "ant"]], columns=["animal1","animal2","animal3", "animal4"])
Я хочу преобразовать все NAN в 0, а все ответы-в 1.
#First I convert all NaNs to 0 and make everything string
test = test.fillna(0)
test = test.astype(str)
Затем я создаю список интересующих столбцов (в данном примере это не имеет смысла, потому что всего 2 столбца, но в моем конкретном случае их много).
op = test.iloc[:,0:2].columns.tolist()
Я бы подумал, что смогу просто сделать это:
test[op] = [1 if x != '0' else 0 for x in test[op]]
Но это не работает, так как преобразует все в 1.
Затем я попытался сделать по каждому столбцу вручную, и это действительно работает:
test['animal1'] = [1 if x != '0' else 0 for x in test['animal1']]
Кто-нибудь знает, почему работает последний способ, но не первый? И любые рекомендации о том, как заставить его работать, будут оценены с благодарностью.
Редактировать/обновление: SeaBean предоставил решение, которое работает (спасибо!!). Мне все равно было бы интересно узнать, почему метод, который я использовал, работал только при выполнении по одному столбцу за раз (вручную).
Комментарии:
1. вы проверили тип этого
x
?2. Смотрите мое редактирование, чтобы объяснить свой запрос о том, почему понимание списка для нескольких столбцов не сработало.
Ответ №1:
Вы можете использовать .notna()
и преобразовать в 0/1 .astype()
следующим образом:
test.notna().astype(int)
Результат:
animal1 animal2 animal3 animal4
0 0 1 1 1
1 1 1 1 1
2 1 0 1 1
3 0 0 1 1
Редактировать
Чтобы объяснить, почему ваш опробованный метод работал только при выполнении его по одному столбцу за раз, но не для нескольких столбцов:
Когда вы работаете над одним столбцом за раз и указываете, например test['animal1']
, в понимании списка, вы повторяете элементы серии Pandas соответствующего столбца. Это позволит выполнить задачу так, как вы ожидаете.
Однако, когда вы делаете это в нескольких столбцах, включая test[op]
в список понимание, здесь вместо серии Панд используется test[op]
фрейм данных. Когда вы повторяете этот фрейм данных, вы получаете только метки столбцов фрейма данных. Вы поймете это, когда попробуете понять следующий список:
[x for x in test[op]]
что дает:
['animal1', 'animal2']
Таким образом, в вашем понимании списка для нескольких столбцов ваше сравнение x != '0'
всегда будет возвращать значение true и давать все 1, поскольку метки столбцов, с которыми вы сравниваете, не содержат «0».
Комментарии:
1. Спасибо за редактирование дополнительного объяснения. Это было очень понятно и полезно!
Ответ №2:
Вы можете использовать .isna() и инвертировать результаты:
print(~test.isna())
animal1 animal2 animal3 animal4
0 False True True True
1 True True True True
2 True False True True
3 False False True True
Если вы предпочитаете иметь 0 и 1, умножьте это на 1:
print((~test.isna())*1)
animal1 animal2 animal3 animal4
0 0 1 1 1
1 1 1 1 1
2 1 0 1 1
3 0 0 1 1