Contar valores únicos con pandas por grupo

Necesito contar valores de ID únicos en cada domain que tengo datos

 ID, domain 123, 'vk.com' 123, 'vk.com' 123, 'twitter.com' 456, 'vk.com' 456, 'facebook.com' 456, 'vk.com' 456, 'google.com' 789, 'twitter.com' 789, 'vk.com' 

Intento df.groupby(['domain', 'ID']).count() Pero quiero obtener

 domain, count vk.com 3 twitter.com 2 facebook.com 1 google.com 1 

Necesitas nunique

 df = df.groupby('domain')['ID'].nunique() print (df) domain 'facebook.com' 1 'google.com' 1 'twitter.com' 2 'vk.com' 3 Name: ID, dtype: int64 

Si necesitas strip ' caracteres:

 df = df.ID.groupby([df.domain.str.strip("'")]).nunique() print (df) domain facebook.com 1 google.com 1 twitter.com 2 vk.com 3 Name: ID, dtype: int64 

O como Jon Clements comentó:

 df.groupby(df.domain.str.strip("'"))['ID'].nunique() 

Puedes retener el nombre de la columna de esta manera:

 df = df.groupby(by='domain', as_index=False).agg({'ID': pd.Series.nunique}) print(df) domain ID 0 fb 1 1 ggl 1 2 twitter 2 3 vk 3 

La diferencia es que nunique() devuelve una serie y agg() devuelve un DataFrame.

En general, para contar valores distintos en una sola columna, puede usar Series.value_counts :

 df.domain.value_counts() #'vk.com' 5 #'twitter.com' 2 #'facebook.com' 1 #'google.com' 1 #Name: domain, dtype: int64 

Para ver cuántos valores únicos en una columna, use Series.nunique :

 df.domain.nunique() # 4 

Para obtener todos estos valores distintos, puede usar unique o drop_duplicates , la ligera diferencia entre las dos funciones es que unique devuelve un numpy.array mientras que drop_duplicates devuelve un pandas.Series :

 df.domain.unique() # array(["'vk.com'", "'twitter.com'", "'facebook.com'", "'google.com'"], dtype=object) df.domain.drop_duplicates() #0 'vk.com' #2 'twitter.com' #4 'facebook.com' #6 'google.com' #Name: domain, dtype: object 

En cuanto a este problema específico, ya que le gustaría contar un valor distinto con respecto a otra variable, además del método groupby proporcionado por otras respuestas aquí, también puede simplemente eliminar los duplicados y luego hacer value_counts() :

 import pandas as pd df.drop_duplicates().domain.value_counts() # 'vk.com' 3 # 'twitter.com' 2 # 'facebook.com' 1 # 'google.com' 1 # Name: domain, dtype: int64 

df.domain.value_counts ()

 >>> df.domain.value_counts() vk.com 5 twitter.com 2 google.com 1 facebook.com 1 Name: domain, dtype: int64 

Para obtener el número de ID diferente para cada domain , puede intentar esto:

 output = df.drop_duplicates() output.groupby('domain').size() 

salida:

  domain facebook.com 1 google.com 1 twitter.com 2 vk.com 3 dtype: int64 

También value_counts usar value_counts , que es un poco menos eficiente. value_counts la mejor respuesta es la de Jezrael usando nunique :

 %timeit df.drop_duplicates().groupby('domain').size() 1000 loops, best of 3: 939 µs per loop %timeit df.drop_duplicates().domain.value_counts() 1000 loops, best of 3: 1.1 ms per loop %timeit df.groupby('domain')['ID'].nunique() 1000 loops, best of 3: 440 µs per loop