2017-01-02 203 views
1

假設我有一個數據幀:大熊貓選擇多列有條件

C1 V1 C2 V2 Cond 
1 2 3 4 X 
5 6 7 8 Y 
9 10 11 12 X 

的語句應該返回:if Cond == X, pick C1 and C2, else pick C2 and V2

輸出數據幀是一樣的東西:

C V 
1 2 
7 8 
9 10 

**編輯:要添加更多一個要求:列的數量可以改變,但遵循一定的命名模式。在這種情況下,選擇其中包含「1」的所有列,否則選擇「2」。我認爲硬編碼的解決方案可能無法正常工作。

+1

可能的複製[Cre用熊貓的ELIF吃了一列](http://stackoverflow.com/questions/18194404/create-column-with-elif-in-pandas) – e4c5

+0

'indexer = {'X':['C1','V1'] ,'Y':['C2','V2']};對於k,v in indexer.items()])中的pd.concat([pd.DataFrame(df.loc [df.Cond == k,v] .values,columns = ['C','V']))'是這樣做的一種方式,但它不保存行的順序。 – Abdou

回答

2

我嘗試用filternumpy.where創造更多的通用的解決方案,爲新的列名稱使用extract

#if necessary sort columns 
df = df.sort_index(axis=1) 

#filter df by 1 and 2 
df1 = df.filter(like='1') 
df2 = df.filter(like='2') 
print (df1) 
    C1 V1 
0 1 2 
1 5 6 
2 9 10 

print (df2) 
    C2 V2 
0 3 4 
1 7 8 
2 11 12 
#np.where need same shape of mask as df1 and df2 
mask = pd.concat([df.Cond == 'X']*len(df1.columns), axis=1) 
print (mask) 
    Cond Cond 
0 True True 
1 False False 
2 True True 

cols = df1.columns.str.extract('([A-Za-z])', expand=False) 
print (cols) 
Index(['C', 'V'], dtype='object') 

print (np.where(mask, df1,df2)) 
Index(['C', 'V'], dtype='object') 
[[ 1 2] 
[ 7 8] 
[ 9 10]] 

print (pd.DataFrame(np.where(mask, df1, df2), index=df.index, columns=cols)) 
    C V 
0 1 2 
1 7 8 
2 9 10 
2
  • dropCond集中於值我從
  • reshape numpy的陣列,所以我可以用布爾值區分
  • 索引第一維度與
  • np.arange(len(df))選擇,一旦爲每一行
  • 索引第二維度與df.Cond.ne('X').mul(1)0爲等於X
  • 構建最終的數據幀

pd.DataFrame(
    df.drop('Cond', 1).values.reshape(3, 2, 2)[ 
     np.arange(len(df)), 
     df.Cond.ne('X').mul(1) 
    ], df.index, ['C', 'V']) 

    C V 
0 1 2 
1 7 8 
2 9 10 
0

您可以嘗試使用類似的方法在this post

首先,定義了幾個功能:

def cond(row): 
    return row['Cond'] == 'X' 

def helper(row, col_if, col_ifnot): 
    return row[col_if] if cond(row) else row[col_ifnot] 

然後,如suming您的數據框被稱爲df

df_new = pd.DataFrame(index=df.index) 
for col in ['C', 'V']: 
    col_1 = col + '1' 
    col_2 = col + '2' 
    df_new[col] = df.apply(lambda row: helper(row, col_1, col_2), axis=1) 

請記住,這種做法可能是大dataframes緩慢,因爲apply沒有利用量化的。但是,即使使用任意列名稱也應該可以工作(只需將['C', 'V']替換爲您的實際列名稱)。

1

如果行的順序不重要,則可以使用df.locdf.append

ndf1 = df.loc[df['Cond'] == 'X', ['C1','V1']] 
ndf2 = df.loc[df['Cond'] == 'Y', ['C2','V2']] 
ndf1.columns = ['C','V'] 
ndf2.columns = ['C','V'] 

result = ndf1.append(ndf2).reset_index(drop=True) 
print(result) 
    C V 
0 1 2 
1 9 10 
2 7 8 
1

DataFrame.where()另一種選擇:

df[['C1', 'V1']].where(df.Cond == "X", df[['C2', 'V2']].values) 

# C1 V1 
#0 1 2 
#1 7 8 
#2 9 10 
+1

太棒了!很優雅的解決方案爲你+1!我爲什麼沒有想到 –