如何按列分组并将其他列的值作为列表返回到pandas中?

时间:2017-07-08 04:01:28

标签: python pandas

我遇到麻烦,将列的值聚合在一起并保留其他列的相应值。我想做类似的事情:grouping rows in list in pandas groupby

但相反,我希望列表/字典(最好是后者)包含多列的值。 此数据框的示例:

DF:

Col1   Col2   Col3
A      xyz     1
A      pqr     2
B      xyz     2
B      pqr     3
B      lmn     1
C      pqr     2

我想要像 -

这样的东西
A {'xyz':1, 'pqr': 2}
B {'xyz':2, 'pqr': 3, 'lmn': 1}
C {'pqr':2}

我试过

df.groupby('Col1')[['Col2', 'Col3']].apply(list) 

这是链接帖子中提到的解决方案的变体,但是没有给我我需要的结果。

从那时起,我还希望将其转换为以下形式的数据框:

  xyz  pqr  lmn
A  1    2    NaN
B  2    3    1
C  NaN  2    NaN

3 个答案:

答案 0 :(得分:1)

最终你想要的是一个数据透视表。

df.pivot_table(index='Col1',columns='Col2',values='Col3')

查看文档以获取更多选项。

答案 1 :(得分:1)

使用pivotunstack

df = df.pivot(index='Col1',columns='Col2',values='Col3')
print (df)
Col2  lmn  pqr  xyz
Col1               
A     NaN  2.0  1.0
B     1.0  3.0  2.0
C     NaN  2.0  NaN
df = df.set_index(['Col1','Col2'])['Col3'].unstack()
print (df)

Col2  lmn  pqr  xyz
Col1               
A     NaN  2.0  1.0
B     1.0  3.0  2.0
C     NaN  2.0  NaN

但是如果:

  

ValueError:索引包含重复的条目,无法重塑

表示重复,需要pivot_tablegroupbymean汇总(可以更改为summedian),最后重新设置为{ {1}}:

unstack

编辑:

print (df) Col1 Col2 Col3 0 A xyz 1 <-same A, xyz 1 A xyz 5 <-same A, xyz 2 A pqr 2 3 B xyz 2 4 B pqr 3 5 B lmn 1 6 C pqr 2 df = df.groupby(['Col1','Col2'])['Col3'].mean().unstack() print (df) Col2 lmn pqr xyz Col1 A NaN 2.0 3.0 (1+5)/2 = 3 B 1.0 3.0 2.0 C NaN 2.0 NaN Col1检查所有重复项:

Col2

EDIT1:

如果重复需要第一行:

print (df[df.duplicated(subset=['Col1','Col2'], keep=False)])
  Col1 Col2  Col3
0    A  xyz     1
1    A  xyz     5

或者最好先按drop_duplicates删除重复项,然后使用第一个或第二个解决方案:

df = df.groupby(['Col1','Col2'])['Col3'].first().unstack()
print (df)
Col2  lmn  pqr  xyz
Col1               
A     NaN  2.0  1.0
B     1.0  3.0  2.0
C     NaN  2.0  NaN

答案 2 :(得分:1)

其中任何一个都不是pandas唯一的解决方案。我提供他们因为我发现探索替代品很有趣。 bincount基础解决方案非常快,但透明度较低。

广告素材解决方案1 ​​
collections.defaultdict和词典理解

from collections import defaultdict

d = defaultdict(dict)
[d[c2].setdefault(c1, c3) for i, c1, c2, c3 in df.itertuples()];
pd.DataFrame(d)

   lmn  pqr  xyz
A  NaN    2  1.0
B  1.0    3  2.0
C  NaN    2  NaN

广告素材解决方案2
pd.factorizenp.bincount

f1, u1 = pd.factorize(df.Col1.values)
f2, u2 = pd.factorize(df.Col2.values)
w = df.Col3.values

n, m = u1.size, u2.size

v = np.bincount(f1 * n + f2, w, n * m).reshape(n, m)
pd.DataFrame(np.ma.array(v, mask=v == 0), u1, u2)

   lmn  pqr  xyz
A  NaN    2  1.0
B  1.0    3  2.0
C  NaN    2  NaN

计时

%timeit df.pivot(index='Col1',columns='Col2',values='Col3')
%timeit df.set_index(['Col1','Col2'])['Col3'].unstack()
%timeit df.groupby(['Col1','Col2'])['Col3'].mean().unstack()
%timeit df.pivot_table(index='Col1',columns='Col2',values='Col3')

%%timeit
d = defaultdict(dict)
[d[c2].setdefault(c1, c3) for i, c1, c2, c3 in df.itertuples()];
pd.DataFrame(d)

%%timeit
f1, u1 = pd.factorize(df.Col1.values)
f2, u2 = pd.factorize(df.Col2.values)
w = df.Col3.values

n, m = u1.size, u2.size

v = np.bincount(f1 * n + f2, w, n * m).reshape(n, m)
pd.DataFrame(np.ma.array(v, mask=v == 0), u1, u2)

小数据

1000 loops, best of 3: 1.11 ms per loop
1000 loops, best of 3: 1.67 ms per loop
1000 loops, best of 3: 1.51 ms per loop
100 loops, best of 3: 4.17 ms per loop

1000 loops, best of 3: 1.18 ms per loop

1000 loops, best of 3: 420 µs per loop

中等数据

from string import ascii_letters
l = list(ascii_letters)
df = pd.DataFrame(dict(
        Col1=np.random.choice(l, 10000),
        Col2=np.random.choice(l, 10000),
        Col3=np.random.randint(10, size=10000)
    )).drop_duplicates(['Col1', 'Col2'])

1000 loops, best of 3: 1.75 ms per loop
100 loops, best of 3: 2.17 ms per loop
100 loops, best of 3: 2.2 ms per loop
100 loops, best of 3: 4.89 ms per loop

100 loops, best of 3: 5.6 ms per loop

1000 loops, best of 3: 549 µs per loop