2017-10-04 3 views
1

J'essaie de sous-créer une base de données basée sur le fait que les regroupements contiennent ou non au moins une occurrence de certains codes.La base de données de sous-ensemble par groupe doit contenir

Considérons cet exemple

import pandas as pd 

df = pd.DataFrame({'cId' : [1, 1, 1, 2, 2, 4, 4, 4, 4, 4], 
        'eId' : [1, 1, 1, 1, 1, 1, 1, 2, 2, 3], 
        'code' :['af', 'af', 'la', 'su', 'su', 'af', 'da', 'da', 'la', 'su'], 
        'data' : [1, 2, 3, 5, 3, 5, 2, 5, 2, 1]}, 
columns=['cId', 'eId', 'code', 'data']) 

df 
Out[10]: 
    cId eId code data 
0 1 1 af  1 
1 1 1 af  2 
2 1 1 la  3 
3 2 1 su  5 
4 2 1 su  3 
5 4 1 af  5 
6 4 1 da  2 
7 4 2 da  5 
8 4 2 la  2 
9 4 3 su  1 

Les inscriptions doivent être regroupées par cId et eId.

Je souhaite ne conserver que les groupes qui ont au moins une occurrence où code dans ['af', 'da'].

Le résultat final devrait être

df 
Out[10]: 
    cId eId code data 
0 1 1 af  1 
1 1 1 af  2 
2 1 1 la  3 
5 4 1 af  5 
6 4 1 da  2 
7 4 2 da  5 
8 4 2 la  2 

Toutes les suggestions?

Répondre

1

Utilisez isin pour les colonnes, duplicated et dernier merge:

df = df.loc[df['code'].isin(['af', 'da']), ['cId','eId']].drop_duplicates().merge(df) 
print (df) 
    cId eId code data 
0 1 1 af  1 
1 1 1 af  2 
2 1 1 la  3 
3 4 1 af  5 
4 4 1 da  2 
5 4 2 da  5 
6 4 2 la  2 

Détail:

print (df.loc[df['code'].isin(['af', 'da']), ['cId','eId']].drop_duplicates()) 
    cId eId 
0 1 1 
5 4 1 
7 4 2 

minutage:

np.random.seed(45) 
N = 100000 
df = pd.DataFrame({'cId': np.random.randint(100, size=N), 
        'eId' :np.random.randint(100, size=N), 
        'code': np.random.choice(['af','la','su','da','na'], size=N, p=(0.001,0.2,0.2,0.001,0.598)), 
        'data' :np.random.randint(10, size=N), }) 


In [68]: %timeit df.loc[df['code'].isin(['af', 'da']), ['cId','eId']].drop_duplicates().merge(df) 
100 loops, best of 3: 15.9 ms per loop 

In [69]: %timeit df.groupby(['cId', 'eId']).filter(lambda x: x['code'].isin(['af', 'da']).any()) 
1 loop, best of 3: 4.01 s per loop 

In [70]: %timeit df[df.groupby(['cId', 'eId'])['code'].transform(lambda x: x.isin(['af', 'da']).any())] 
1 loop, best of 3: 4.05 s per loop 
+1

Im allant pour votre solution alors, car il semble être le plus rapide. – mortysporty

1

options 1
Utilisez filter

In [610]: df.groupby(['cId', 'eId']).filter(lambda x: x['code'].isin(['af', 'da']).any()) 
Out[610]: 
    cId eId code data 
0 1 1 af  1 
1 1 1 af  2 
2 1 1 la  3 
5 4 1 af  5 
6 4 1 da  2 
7 4 2 da  5 
8 4 2 la  2 

options 2
Utilisez transform

In [612]: df[df.groupby(['cId', 'eId'])['code'].transform(lambda x: x.isin(['af', 'da']).any())] 
Out[612]: 
    cId eId code data 
0 1 1 af  1 
1 1 1 af  2 
2 1 1 la  3 
5 4 1 af  5 
6 4 1 da  2 
7 4 2 da  5 
8 4 2 la  2 
+0

rapide comme l'éclair :) – mortysporty