熊猫 - 计算多个条件

时间:2016-06-26 20:13:57

标签: python pandas dataframe group-by

在python中有一个数据框:

CASE    TYPE
1          A
1          A
1          A
2          A
2          B
3          B
3          B
3          B

如何创建一个结果数据框,它可以产生所有情况,并且可以产生" A"如果案件只有" A'"分配," B"如果它只是" B'"或"混合"如果案件既有A又有B?

结果将是:

Case     Type
1        A
2        MIXED
3        B

4 个答案:

答案 0 :(得分:2)

这是一个选项,我们首先按CASE组收集TYPE作为列表,然后检查唯一TYPE的length,如果它大于1,则返回{ {1}}否则TYPE本身:

MIXED

答案 1 :(得分:2)

df['NTYPES'] = df.groupby('CASE').transform(lambda x: x.nunique())
df.loc[df.NTYPES > 1, 'TYPE'] = 'MIXED'
df.groupby('TYPE', as_index=False).first().drop('NTYPES', 1)

    TYPE  CASE
0      A     1
1      B     3
2  MIXED     2

答案 2 :(得分:1)

这有点难看,但不是那么缓慢的解决方案:

In [154]: df
Out[154]:
    CASE TYPE
0      1    A
1      1    A
2      1    A
3      2    A
4      2    B
5      3    B
6      3    B
7      3    B
8      4    C
9      4    C
10     4    B

In [155]: %paste
(df.groupby('CASE')['TYPE']
   .apply(lambda x: x.head(1) if x.nunique() == 1 else pd.Series(['MIX']))
   .reset_index()
   .drop('level_1', 1)
)
## -- End pasted text --
Out[155]:
   CASE TYPE
0     1    A
1     2  MIX
2     3    B
3     4  MIX

时间:对800K行DF:

In [191]: df = pd.concat([df] * 10**5, ignore_index=True)

In [192]: df.shape
Out[192]: (800000, 3)

In [193]: %timeit Psidom(df)
1 loop, best of 3: 235 ms per loop

In [194]: %timeit capitalistpug(df)
1 loop, best of 3: 419 ms per loop

In [195]: %timeit Alberto_Garcia_Raboso(df)
10 loops, best of 3: 112 ms per loop

In [196]: %timeit MaxU(df)
10 loops, best of 3: 80.4 ms per loop

答案 3 :(得分:1)

这是一个(公认的过度设计)解决方案,可避免循环群组和DataFrame.apply(这些很慢,因此如果数据集足够大,避免它们可能会变得很重要。)

import pandas as pd
df = pd.DataFrame({'CASE': [1]*3 + [2]*2 + [3]*3,
                   'TYPE': ['A']*4 + ['B']*4})

我们按CASE分组并计算TYPE AB的相对频率:

grouped = df.groupby('CASE')
vc = (grouped['TYPE'].value_counts(normalize=True)
                     .unstack(level=0)
                     .fillna(0))

这是vc的样子

CASE   1    2    3
TYPE
A      1.0  0.5  0.0
B      0.0  0.5  0.0

请注意,所有信息都包含在第一行中。将所述行切换为具有pd.cut的区域,可得到所需的结果:

tolerance = 1e-10
bins = [-tolerance, tolerance, 1-tolerance, 1+tolerance]
types = pd.cut(vc.loc['A'], bins=bins, labels=['B', 'MIXED', 'A'])

我们得到:

CASE
1        A
2    MIXED
3        B
Name: A, dtype: category
Categories (3, object): [B < MIXED < A]

为了更好地衡量,我们可以重命名types系列:

types.name = 'TYPE'