使用Pandas

时间:2017-09-26 07:39:04

标签: python pandas dataframe group-by pandas-groupby

我有一个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中所做的那样。 我们怎么能在熊猫中做到这一点?

4 个答案:

答案 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_indexcumcount一起用于新列名称的每组计数,并按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.applySeries构造函数的解决方案:

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