簡體   English   中英

僅使用一行交換 pandas 數據框中選定行的列值的正確語法是什么?

[英]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.selectdf.where ie來完成此df.where

選項1np.select

df[['L','R']] = pd.np.select(df['VALUE'] == 1, df[['R','L']].values, df[['L','R']].values)

選項2df.where

df[['L','R']] = df[['R','L']].where(df['VALUE'] == 1, df[['L','R']].values)

選項3df.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM