Nombre de pandas équivalent (distinct)


289

J'utilise pandas comme substitut db car j'ai plusieurs bases de données (oracle, mssql, etc.) et je ne peux pas faire une séquence de commandes vers un équivalent SQL.

J'ai une table chargée dans un DataFrame avec quelques colonnes:

YEARMONTH, CLIENTCODE, SIZE, .... etc etc

En SQL, compter le nombre de clients différents par an serait:

SELECT count(distinct CLIENTCODE) FROM table GROUP BY YEARMONTH;

Et le résultat serait

201301    5000
201302    13245

Comment puis-je faire cela chez les pandas?


J'ai fait table.groupby (['YEARMONTH']) ['CLIENTCODE']. Unique () et suis venu avec deux séries indexées par YEARMONTH et avec toutes les valeurs uniques. Comment compter le montant des valeurs sur chaque série?
Adriano Almeida

Pour certains, c'est value_countspeut-être la réponse que vous recherchez: pandas.pydata.org/pandas-docs/stable/generated/…
sachinruk

Réponses:


434

Je crois que c'est ce que vous voulez:

table.groupby('YEARMONTH').CLIENTCODE.nunique()

Exemple:

In [2]: table
Out[2]: 
   CLIENTCODE  YEARMONTH
0           1     201301
1           1     201301
2           2     201301
3           1     201302
4           2     201302
5           2     201302
6           3     201302

In [3]: table.groupby('YEARMONTH').CLIENTCODE.nunique()
Out[3]: 
YEARMONTH
201301       2
201302       3

2
Que faire si j'ai plusieurs colonnes que je veux être unique ensemble, comme dans .drop_duplicates (subset = ['col1', 'col2'])?
ErnestScribbler

4
Comment accéder à ce décompte unique. Comme il n'y a pas de nom de colonne
Tarun Khaneja

Merci beaucoup, j'ai utilisé ce style en sortie de rééchantillonnage. df_watch_record.resample ('M'). user.nunique () compte le nombre d'utilisateurs uniques qui ont regardé un film par mois.
Mehdi Kazemi

1
et triez-les avec table.groupby ('YEARMONTH'). CLIENTCODE.nunique (). sort_values ​​(ascendant = False)
wllbll

Est-il possible de récupérer l'identifiant de groupe après nunique? Essayez comme je pourrais, je ne peux pas trouver un moyen, car le résultat de cette réponse est un Series, pas un DataFrame.
Josh Hansen

93

Voici une autre méthode, très simple, disons que votre nom de trame de données est daatet que le nom de la colonne estYEARMONTH

daat.YEARMONTH.value_counts()

1
J'aime cette réponse. Comment puis-je utiliser cette méthode si mon nom de colonne a un '.' en elle (par exemple «ck.Class»)? Merci

5
daat ['ck.Class']. value_counts ()
StatguyUser

28
Cela ne répond pas à la question posée.
Aaron Schumacher

6
cela compte le nombre d'observations dans chaque groupe, et non la valeur unique d'une certaine colonne de chaque groupe.
Jason Goal

2
Ceci est la mauvaise réponse; cela ne reflète pas l' DISTINCTexigence de la question! De plus, il n'inclut pas le nombre de NaN!
Corey Levinson

47

Chose intéressante, est très souvent len(unique())plusieurs fois (3x-15x) plus rapide que nunique().


11
Tu veux dire ça? .CLIENTCODE.apply(lambda x: len(x.unique())), d' ici
user4015990

6
@ user32185 vous devrez le déposer dans un applyappel avec un lambda. Par exemple, df.groupby('YEARMONTH')['CLIENTCODE'].apply(lambda x: x.unique().shape[0]).
3novak

3
La syntaxe n'est pas complètement claire, je n'ai len(df['column'].unique())pas utilisé la fonction lambda
mlh351

J'ai obtenu TypeError: object of type 'method' has no len()des Chen'scommentaires, 3novak'stravaillé pour moi.
Jason Goal

4

En utilisant crosstab, cela renverra plus d'informations quegroupby nunique

pd.crosstab(df.YEARMONTH,df.CLIENTCODE)
Out[196]: 
CLIENTCODE  1  2  3
YEARMONTH          
201301      2  1  0
201302      1  2  1

Après un peu de modification, donnez le résultat

pd.crosstab(df.YEARMONTH,df.CLIENTCODE).ne(0).sum(1)
Out[197]: 
YEARMONTH
201301    2
201302    3
dtype: int64

Comment puis-je exporter cela en deux colonnes YEARMONTHet count. Puis-je également définir le nombre par ordre décroissant?
Murtaza Haji

3

J'utilise également, nuniquemais ce sera très utile si vous devez utiliser une fonction d'agrégation comme 'min', 'max', 'count' or 'mean'etc.

df.groupby('YEARMONTH')['CLIENTCODE'].transform('nunique') #count(distinct)
df.groupby('YEARMONTH')['CLIENTCODE'].transform('min')     #min
df.groupby('YEARMONTH')['CLIENTCODE'].transform('max')     #max
df.groupby('YEARMONTH')['CLIENTCODE'].transform('mean')    #average
df.groupby('YEARMONTH')['CLIENTCODE'].transform('count')   #count

0

Avec la nouvelle version de pandas, il est facile d'obtenir en tant que trame de données

unique_count = pd.groupby(['YEARMONTH'], as_index=False).agg(uniq_CLIENTCODE =('CLIENTCODE',pd.Series.count))

0

Voici une approche pour avoir un décompte distinct sur plusieurs colonnes. Ayons quelques données:

data = {'CLIENT_CODE':[1,1,2,1,2,2,3],
        'YEAR_MONTH':[201301,201301,201301,201302,201302,201302,201302],
        'PRODUCT_CODE': [100,150,220,400,50,80,100]
       }
table = pd.DataFrame(data)
table

CLIENT_CODE YEAR_MONTH  PRODUCT_CODE
0   1       201301      100
1   1       201301      150
2   2       201301      220
3   1       201302      400
4   2       201302      50
5   2       201302      80
6   3       201302      100

Maintenant, listez les colonnes qui vous intéressent et utilisez groupby dans une syntaxe légèrement modifiée:

columns = ['YEAR_MONTH', 'PRODUCT_CODE']
table[columns].groupby(table['CLIENT_CODE']).nunique()

On obtient:

YEAR_MONTH  PRODUCT_CODE CLIENT_CODE        
1           2            3
2           2            3
3           1            1

0

Distinct de la colonne avec des agrégations sur d'autres colonnes

Pour obtenir le nombre distinct de valeurs pour n'importe quelle colonne ( CLIENTCODEdans votre cas), nous pouvons utiliser nunique. Nous pouvons passer l'entrée comme un dictionnaire dans la aggfonction, avec des agrégations sur d'autres colonnes:

grp_df = df.groupby('YEARMONTH').agg({'CLIENTCODE': ['nunique'],
                                      'other_col_1': ['sum', 'count']})

# to flatten the multi-level columns
grp_df.columns = ["_".join(col).strip() for col in grp_df.columns.values]

# if you wish to reset the index
grp_df.reset_index(inplace=True)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.