2016-11-10 51 views
2

我想通過一列上的數據幀進行分組,從每個組中的一行保留多個列,並將來自其他行的字符串連接到基於一列值的多個列中。下面是一個例子...Python熊貓groupby條件連接字符串到多個列

df = pd.DataFrame({'test' : ['a','a','a','a','a','a','b','b','b','b'], 
    'name' : ['aa','ab','ac','ad','ae','ba','bb','bc','bd','be'], 
    'amount' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 9.5], 
    'role' : ['x','y','y','x','x','z','y','y','z','y']}) 

DF

 amount name role test 
0  1.0 aa  x  a 
1  2.0 ab  y  a 
2  3.0 ac  y  a 
3  4.0 ad  x  a 
4  5.0 ae  x  a 
5  6.0 ba  z  a 
6  7.0 bb  y  b 
7  8.0 bc  y  b 
8  9.0 bd  z  b 
9  9.5 be  y  b 

我想GROUPBY上測試,保留名稱和金額,當角色= 'Z',創建一個列(姑且稱之爲X)它在role ='x'時連接name的值,當role ='y'時連接name的值連接另一個列(我們稱之爲Y)。 [由''分隔的連接值; ']可能有零到多行的角色='x',零到許多行的角色='y'和一行角色='z'每個值的測試。對於X和Y,如果該測試沒有該角色的行,則這些值可以爲null。對於所有具有role ='x'或'y'的行,金額值將被刪除。所需的輸出會是這樣的:

 test name  amount  X    Y 
0 a  ba   6.0  aa; ad; ae  ab; ac 
1 b  bd   9.0  None   bb; bc; be 

對於串接的一部分,我發現x.ix[x.role == 'x', X] = "{%s}" % '; '.join(x['name']),我也許能夠重複y的。我根據name = x[x.role == 'z'].name.first()的名字和金額嘗試了幾件事。我也嘗試去定義函數和lambda函數的路徑,但都沒有成功。欣賞任何想法。

回答

1

可以groupby後的apply功能創建自定義列如下,其中g可以考慮在測試列中的單個值的子數據幀,因爲你想多列返回,你需要創建一個Series對象對於每個組,其中索引是在結果中的對應的標頭:

df.groupby('test').apply(lambda g: pd.Series({'name': g['name'][g.role == 'z'].iloc[0], 
               'amount': g['amount'][g.role == 'z'].iloc[0], 
               'X': '; '.join(g['name'][g.role == 'x']), 
               'Y': '; '.join(g['name'][g.role == 'y']) 
              })).reset_index() 

enter image description here

1
# set index and get crossection where test is 'z' 
z = df.set_index(['test', 'role']).xs('z', level='role') 
# get rid of 'z' rows and group by 'test' and 'role' to join names 
xy = df.query('role != "z"').groupby(['test', 'role'])['name'].apply(';'.join).unstack() 
# make columns of xy upper case 
xy.columns = xy.columns.str.upper() 

pd.concat([z, xy], axis=1).reset_index() 

enter image description here