我有一个df
id name value
1 abc 10
1 qwe 23
1 zxc 12
2 sdf 10
2 wed 23
2 abc 12
2 mnb 11
我想将此数据框重塑为:
id n1 n2 n3 n4
1 abc qwe zxc 0
2 sdf wed abc mnb
我们可以看到id = 1有3行,id = 2有4行。 因此取代最后一栏n4 = 0这样的事情。
这是测试数据帧,可能会发生这样的情况,对于id也可能会有1-2行。
就像我们在R-dcast中所做的那样。 我们怎么能在熊猫中做到这一点?
答案 0 :(得分:2)
可能有点矫枉过正
f, u = pd.factorize(df.id.values)
b = np.bincount(f)
n, m = u.size, b.max()
c = np.arange(f.size) - np.arange(n).repeat(b) * (m - 1)
v = np.zeros((n, m), dtype=object)
v[f, c] = df.name.values
pd.DataFrame(
v, pd.Index(u, name='id'),
['n{}'.format(i) for i in range(1, m + 1)]
).reset_index()
id n1 n2 n3 n4
0 1 abc qwe zxc 0
1 2 sdf wed abc mnb
答案 1 :(得分:2)
您可以转到str
路线,并在groupby
之后使用一些正则表达式替换和拆分。
df.groupby('id').name.apply(lambda x: str(list(x)))\
.str.replace("[\[\],']", "")\
.str.split(expand=True).fillna(0)\
.rename(columns = lambda x: 'n{}'.format(x + 1))
n1 n2 n3 n4
id
1 abc qwe zxc 0
2 sdf wed abc mnb
答案 2 :(得分:1)
您可以将set_index
与cumcount
一起用于新列名称的每组计数,并按unstack
重新整形,最后重命名列:
df = (df.set_index(['id', df.groupby('id').cumcount()])['name']
.unstack(fill_value=0)
.rename(columns = lambda x: 'n{}'.format(x + 1))
.reset_index())
print (df)
id n1 n2 n3 n4
0 1 abc qwe zxc 0
1 2 sdf wed abc mnb
使用DataFrame
构造函数的解决方案,原始数据中没有NaN值:
df1 = df.groupby('id')['name'].apply(list)
print (df1)
id
1 [abc, qwe, zxc]
2 [sdf, wed, abc, mnb]
Name: name, dtype: object
df = (pd.DataFrame(df1.values.tolist(), index=df1.index)
.fillna(0)
.rename(columns = lambda x: 'n{}'.format(x + 1))
.reset_index())
print (df)
id n1 n2 n3 n4
0 1 abc qwe zxc 0
1 2 sdf wed abc mnb
使用GroupBy.apply
和Series
构造函数的解决方案:
df1 = (df.groupby('id')['name'].apply(lambda x: pd.Series(x.values, index=range(1,len(x)+1)))
.unstack(fill_value=0)
.add_prefix('n')
.reset_index())
print (df1)
id n1 n2 n3 n4
0 1 abc qwe zxc 0
1 2 sdf wed abc mnb
答案 3 :(得分:1)
使用dfply
包可以像R dcast
一样。
# for Python3 only
pip install dfply
使用spread
的{{1}}功能。
dfply