[英]What is correct syntax to swap column values for selected rows in a pandas data frame using just one line?
我正在使用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
屬性,則會得到以下交換 output:
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 賦值語句中禁用此“列順序自動更正”,以便在不創建不必要的臨時變量的情況下實現交換?
一種避免列名對齊的方法是通過.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
這里要注意的關鍵是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
您也可以使用np.select
和df.where
ie來完成此df.where
選項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
恕我直言, df.update(df.loc[m].rename({'L': 'R', 'R': 'L'}, axis=1))
是最好的。
正如 @cs95 在這個答案的評論中提到的, df.update(df.loc[m].rename({'L': 'R', 'R': 'L'}, axis=1))
將起作用.
為什么更好?
因為它同時支持 NumPy 和 DataFrame 掩碼。
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)
df_mask = df['VALUE'] == 1
df.update(df.loc[df_mask].rename({'L': 'R', 'R': 'L'}, axis=1))
df
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)
np_mask = df['VALUE'].values == 1
df.update(df.loc[np_mask].rename({'L': 'R', 'R': 'L'}, axis=1))
df
這樣,如果作為function使用,用戶可以給出靈活的索引方式。
此外,為了安全起見,如果使用 NumPy 索引,它也支持iloc
而不是loc
。 遺憾的是, iloc
不支持版本“1.3.5”的 DataFrame 索引。
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)
np_mask = df['VALUE'].values == 1
df.update(df.iloc[np_mask].rename({'L': 'R', 'R': 'L'}, axis=1))
df
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.