输入数据是dataframe
[
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
]
对于相同的[name1,name2],将data1移动到data2。我怎么能用python做到这一点?与熊猫? 类似的主题" Python Pandas - 合并大多数重复的行",但我无法找到答案。
答案 0 :(得分:2)
您可以set_index
使用由cumcount
创建的列name1
和Series
,然后按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
答案 1 :(得分: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