Что такое правильный синтаксис для обмена значениями столбцов для выбранных строк в кадре данных pandas, используя только одну строку?
Я использую pandas версию 0.14.1 с Python 2.7.5, и у меня есть кадр данных с тремя столбцами, например:
import pandas as pd
d = {'L': ['left', 'right', 'left', 'right', 'left', 'right'],
'R': ['right', 'left', 'right', 'left', 'right', 'left'],
'VALUE': [-1, 1, -1, 1, -1, 1]}
df = pd.DataFrame(d)
idx = (df['VALUE'] == 1)
приводит к кадру данных, который выглядит следующим образом:
L R VALUE
0 left right -1
1 right left 1
2 left right -1
3 right left 1
4 left right -1
5 right left 1
Для строк, где VALUE == 1
, я хотел бы поменять содержимое левого и правого столбцов, чтобы все "левые" значения попадали в столбце "L", а "правые" значения заканчивались под столбцом "R".
Уже определив переменную idx
выше, я могу легко сделать это только в трех строках, используя временную переменную следующим образом:
tmp = df.loc[idx,'L']
df.loc[idx,'L'] = df.loc[idx,'R']
df.loc[idx,'R'] = tmp
однако это кажется действительно неуклюжим и неэлегантным синтаксисом для меня; неужели pandas поддерживает что-то более кратким? Я заметил, что если я поменяю порядок столбцов во вводе на атрибут .loc
фрейма данных, тогда я получаю следующий файл с заменой:
In [2]: print(df.loc[idx,['R','L']])
R L
1 left right
3 left right
5 left right
Это говорит о том, что я должен иметь возможность реализовать тот же обмен, что и выше, используя только следующую строку:
df.loc[idx,['L','R']] = df.loc[idx,['R','L']]
Однако, когда я на самом деле пытаюсь это сделать, ничего не происходит - столбцы остаются неактивными. Как будто pandas автоматически распознает, что я поставил столбцы в неправильном порядке в правой части оператора присваивания и автоматически исправляет проблему. Есть ли способ отключить эту "автокорреляцию порядка столбцов" в операторах присваивания pandas, чтобы реализовать своп без создания ненужных временных переменных?
Ответы
Ответ 1
Одним из способов избежать выравнивания по именам столбцов было бы падение до базового массива с помощью .values
:
In [33]: df
Out[33]:
L R VALUE
0 left right -1
1 right left 1
2 left right -1
3 right left 1
4 left right -1
5 right left 1
In [34]: df.loc[idx,['L','R']] = df.loc[idx,['R','L']].values
In [35]: df
Out[35]:
L R VALUE
0 left right -1
1 left right 1
2 left right -1
3 left right 1
4 left right -1
5 left right 1
Ответ 2
Ключевым моментом здесь является то, что pandas пытается автоматически выравнивать строки и столбцы с использованием имен индексов и столбцов. Следовательно, вам нужно как-то сказать pandas игнорировать имена столбцов. Один из способов - это @DSM, путем преобразования в массив numpy. Другой способ - переименовать столбцы:
>>> df.loc[idx] = df.loc[idx].rename(columns={'R':'L','L':'R'})
L R VALUE
0 left right -1
1 left right 1
2 left right -1
3 left right 1
4 left right -1
5 left right 1
Ответ 3
Вы также можете сделать это с помощью np.select
и df.where
i.e
Вариант 1: np.select
df[['L','R']] = pd.np.select(df['VALUE'] == 1, df[['R','L']].values, df[['L','R']].values)
Вариант 2: df.where
df[['L','R']] = df[['R','L']].where(df['VALUE'] == 1, df[['L','R']].values)
Вариант 3: df.mask
df[['L','R']] = df[['L','R']].mask( df['VALUE'] == 1, df[['R','L']].values)
Вывод:
L R VALUE
0 left right -1
1 left right 1
2 left right -1
3 left right 1
4 left right -1
5 left right 1