枚举数据框中的组

时间:2017-08-18 17:53:27

标签: python pandas pandas-groupby

我有下表

date        ui  mw  maxw    tC  HL    msurp
01/03/2004  A   10   10     eC  0.25   0.1
01/04/2004  A   10   10     eC  0.25   -0.1
01/03/2004  B   20   20     bC  0.5    0.3
01/03/2004  B   20   20     bC  0.25    0.3

我要做的是在此表中添加一列,基本上列举了ui,mw,maxw,tC和HL的唯一组合并枚举

所以例如在上表中

ui,mw,maxw,tC和HL的唯一组合是

 A,10, 10, eC, 0.25
 B,20, 20, bC, 0.5
 B,20, 20, bC, 0.5

共有3个,所以输出应该是

date        ui  mw  maxw    tC  HL    msurp  counter
01/03/2004  A   10   10     eC  0.25   0.1    1
01/04/2004  A   10   10     eC  0.25   -0.1   1
01/03/2004  B   20   20     bC  0.5    0.3    2
01/03/2004  B   20   20     bC  0.25    0.3   3

2 个答案:

答案 0 :(得分:9)

选项1
pd.Series.factorize

df.assign(
   counter=df[['ui', 'mw', 'maxw', 'tC', 'HL']].apply(tuple, 1).factorize()[0] + 1)

         date ui  mw  maxw  tC    HL  msurp  counter
0  01/03/2004  A  10    10  eC  0.25    0.1        1
1  01/04/2004  A  10    10  eC  0.25   -0.1        1
2  01/03/2004  B  20    20  bC  0.50    0.3        2
3  01/03/2004  B  20    20  bC  0.25    0.3        3

选项1.5
选项1更令人讨厌的版本,但应该更快

df.assign(
    counter=pd.factorize(list(zip(
        *[df[c].values.tolist() for c in ['ui', 'mw', 'maxw', 'tC', 'HL']]
    )))[0] + 1
)

         date ui  mw  maxw  tC    HL  msurp  counter
0  01/03/2004  A  10    10  eC  0.25    0.1        1
1  01/04/2004  A  10    10  eC  0.25   -0.1        1
2  01/03/2004  B  20    20  bC  0.50    0.3        2
3  01/03/2004  B  20    20  bC  0.25    0.3        3

选项2
@ ayhan的答案(如果他发布,将会删除)

df.assign(
    counter=df.groupby(['ui', 'mw', 'maxw', 'tC', 'HL']).ngroup() + 1)

         date ui  mw  maxw  tC    HL  msurp  counter
0  01/03/2004  A  10    10  eC  0.25    0.1        1
1  01/04/2004  A  10    10  eC  0.25   -0.1        1
2  01/03/2004  B  20    20  bC  0.50    0.3        3
3  01/03/2004  B  20    20  bC  0.25    0.3        2

<强>时序
以下代码

(lambda r: r.div(r.min(1), 0).assign(best=lambda x: x.idxmin(1)))(results)

             pir1      pir2     ayhan   best
100     17.260639  1.000000  3.438354   pir2
300     30.550010  1.000000  2.598456   pir2
1000    43.201163  1.000000  1.236190   pir2
3000    61.593932  1.000000  1.025420   pir2
10000  127.003138  2.177171  1.000000  ayhan

enter image description here

pir1 = lambda d: d.assign(counter=d[['ui', 'mw', 'maxw', 'tC', 'HL']].apply(tuple, 1).factorize()[0] + 1)
pir2 = lambda d: d.assign(counter=pd.factorize(list(zip(*[d[c].values.tolist() for c in ['ui', 'mw', 'maxw', 'tC', 'HL']])))[0] + 1)
ayhan = lambda d: d.assign(counter=d.groupby(['ui', 'mw', 'maxw', 'tC', 'HL']).ngroup() + 1)

results = pd.DataFrame(
    index=[100, 300, 1000, 3000, 10000],
    columns='pir1 pir2 ayhan'.split(),
    dtype=float
)

for i in results.index:
    d = pd.concat([df] * i, ignore_index=True)
    for j in results.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        results.set_value(i, j, timeit(stmt, setp, number=10))

results.plot(loglog=True)

答案 1 :(得分:2)

像ayhan的回答一样,假设顺序并不重要

df[['ui','mw','maxw','tC','HL']].T.apply(lambda x : ','.join(x.astype(str))).astype('category').cat.codes


Out[1247]: 
0    0
1    0
2    2
3    1
dtype: int8

正如你所说我可以通过这个聚合而不是通过[ui,mw,maxw等

指定分组

只需执行此操作,然后groupby('counter')

 df['counter']=df[['ui','mw','maxw','tC','HL']].T.apply(lambda x : ','.join(x.astype(str)))