2017-07-26 68 views
2

輸入數據是數據框Python的合併主要是重複的行,列拆分到其他列

[ 
name1 name2 data1 data2 
a  x  1  "" 
a  y  2  "" 
b  x  3  "" 
b  y  4  "" 
a  x  5  "" 
a  y  6  "" 
b  x  7  "" 
b  y  8  "" 
] 

我要的是

[ 
name1 name2 data1 data2 
a  x  1  5 
a  y  2  6 
b  x  3  7 
b  y  4  8 
] 

爲相同[1,名稱],移動數據1到數據2。我如何用python來做到這一點?與熊貓? 類似主題「Python Pandas - 合併大部分重複行」,但我找不到答案。

回答

2

可以使用set_indexcumcount創建的列name1Series然後unstack重塑。

末重命名列,並通過reset_index創建index列:

df = df.set_index(['name1','name2', df.groupby(['name1','name2']).cumcount()])['data1'] \ 
     .unstack().rename(columns = lambda x: 'data' + str(x + 1)).reset_index() 
print (df) 
    name1 name2 data1 data2 
0  a  x  1  5 
1  a  y  2  6 
2  b  x  3  7 
3  b  y  4  8 

另一種解決方案是創建list,然後新df通過DataFrame構造:

df1 = df.groupby(['name1','name2'])['data1'].apply(list) 
df = pd.DataFrame(df1.values.tolist(), index=df1.index) 
df = df.rename(columns = lambda x: 'data' + str(x + 1)).reset_index() 
print (df) 
    name1 name2 data1 data2 
0  a  x  1  5 
1  a  y  2  6 
2  b  x  3  7 
3  b  y  4  8 
+0

無法找到簡單的方法來爆炸列表...放棄... +1 –

+0

@cᴏʟᴅsᴘᴇᴇᴅ - 謝謝。 – jezrael

+1

@cᴏʟᴅsᴘᴇᴇᴅ不要放棄! – piRSquared

1

選項1
使用defaultdict

from collections import defaultdict 

d = defaultdict(list) 
[d[(n1, n2)].append(d1) for n1, n2, d1, d2 in df.values]; 

pd.DataFrame(
    d, [1, 2] 
).T.add_prefix('data').rename_axis(['name1', 'name2']).reset_index() 

    name1 name2 data1 data2 
0  a  x  1  5 
1  a  y  2  6 
2  b  x  3  7 
3  b  y  4  8 

選項2
使用numba

from numba import njit 

@njit 
def plc(f, v): 
    m = np.bincount(f).max() 
    n = f.max() + 1 
    a = np.arange(n * m).reshape(n, m) * 0 
    j = np.arange(n) * 0 
    for x, y in zip(f, v): 
     a[x, j[x]] = y 
     j[x] += 1 
    return a 

f, u = pd.Series(zip(df.name1.values, df.name2.values)).factorize() 

new = np.column_stack([np.array(u.tolist()), plc(f, df.data1.values)]) 

pd.DataFrame(new, columns='name1 name2 data1 data2'.split()) 

    name1 name2 data1 data2 
0  a  x  1  5 
1  a  y  2  6 
2  b  x  3  7 
3  b  y  4  8 

時序
小數據

%%timeit 
f, u = pd.Series(zip(df.name1.values, df.name2.values)).factorize() 

new = np.column_stack([np.array(u.tolist()), plc(f, df.data1.values)]) 

pd.DataFrame(new, columns='name1 name2 data1 data2'.split()) 

############################################################### 

%%timeit 
d = defaultdict(list) 
[d[(n1, n2)].append(d1) for n1, n2, d1, d2 in df.values]; 

pd.DataFrame(d, [1, 2]).T.add_prefix('data').rename_axis(['name1', 'name2']).reset_index() 

############################################################### 

%%timeit 
df1 = df.groupby(['name1','name2'])['data1'].apply(list) 
df2 = pd.DataFrame(df1.values.tolist(), index=df1.index) 
df2.rename(columns = lambda x: 'data' + str(x + 1)).reset_index() 

#-------------------------------------------------------------- 

1000 loops, best of 3: 400 µs per loop 
100 loops, best of 3: 2.23 ms per loop 
100 loops, best of 3: 2.82 ms per loop 
+0

這很好:)在速度測試中它會怎麼樣? –

+0

超過這個小數據集:我的時鐘在'2.22 ms'與'2.87 ms' – piRSquared

+0

@cᴏʟᴅsᴘᴇᴇᴅ增加了另一個( - : – piRSquared