Датафрейм:
col1 col2
A 0
A 1
A nan
B 0
B 1
C and so on...
Я пытаюсь изменить 1 на 0, 0 на 1, и nan остается таким же в col2, где col1=='A'.
Код пока:
df.loc[(df.col1=='A') & (df.col2==0),'col2'] = 2
df.loc[(df.col1=='A') & (df.col2==1),'col2'] = 0
df.loc[(df.col1=='A') & (df.col2==2),'col2'] = 1
# Hope you understand why I am converting 0 to 2 first then to 1.
# Because if I convert all zeroes to 1 then all 1's will be converted to
# 0 in subsequent conversion.
Уникальные значения в col2: 0,1 и nan. Есть ли правильный/лучший способ сделать это? Кроме того, есть ли способ напрямую поменять местами эти числа вместо операторов присваивания?
Одно решение с использованием Series.where
и astype(bool)
с ~
(оператор НЕ), а затем обратно к astype(int)
. Затем используйте loc
с boolean indexing
, чтобы назначить обратно DataFrame
:
df.loc[df.col1.eq('A'), 'col2'] = df.col2.where(df.col2.isna(),
(~df.col2.astype(bool)).astype(int))
[вне]
col1 col2
0 A 1.0
1 A 0.0
2 A NaN
3 B 0.0
4 B 1.0
5 C NaN
@ Загадочные извинения, я добавил фильтр для переключения значений, где только col1=='A'
. И да, isna
— это метод, доступный для Series
Это работает, спасибо! У меня только один вопрос. Если я сделаю len(LHS) в вашем коде и len(RHS), я получу разные числа. Не должна ли длина быть одинаковой в пандах при присвоении значений. Как панды следят за тем, чтобы из RHS использовались правильные позиции?
Это потому, что LHS фильтруется (включает только строки, где col1
равно «A»)... RHS не фильтруется, он включает каждую строку в DataFrame. При назначении pandas выровняет индекс из LHS и RHS, чтобы обновить значения в DataFrame. Таким образом, в этом примере значения индексов [0, 1, 2]
будут обновлены до новых значений индексов [0, 1, 2]
из RHS.
Окей, так что просто из любопытства, если я перетасую RHS, будет ли это все еще работать, потому что индекс не изменится, изменится только порядок значений, то есть [0, 1, 2] станет [2, 0, 1 ]?
Да, точно. Вы можете попробовать это сами, подключив .sample(frac=1)
к RHS. Он будет случайным образом перемешивать Series
, но все равно должен выводить тот же конечный результат.
В этом случае вы также можете использовать свою функцию в сочетании с apply()
.
# import pandas
import pandas as pd
# make a sample data
list_of_rows = [
{'col1': A, 'col2': 1},
{'col1': A, 'col2': 0},
{'col1': A, 'col2': None},
{'col1': B, 'col2': 0},
{'col1': B, 'col2': 1},
{'col1': B, 'col2': None},
]
# make a pandas data frame
df = pd.DataFrame(list_of_rows)
# define a function
def change_values(row):
if row['col2'] == 0:
return 1
if row['col2'] == 1:
return 0
return row['col2']
# apply function to dataframe
df['col2'] = df.apply(lambda row: change_values(row), axis=1)
I am trying to change 1 to 0, 0 to 1 and nan stays as such in col2 wherever col1=='A'.
использовать нп.где
df['col2] = np.where(df['col1'] == 'A', np.where(df['col2'] == 1, 0 , np.where(df['col2'].isnull() == True, df['col2'],1)),df['col2'])
Выход
col1 col2
0 A 1.0
1 A 0.0
2 A NaN
3 B 0.0
4 B 1.0
5 C 0.0
фильтры для col1=='A' отсутствуют, и я не думаю, что isna применима для сериалов, не так ли?