Python Panda’s: draaitabel met aggfunc = count unique unique

Deze code:

df2 = (
    pd.DataFrame({
        'X' : ['X1', 'X1', 'X1', 'X1'], 
        'Y' : ['Y2', 'Y1', 'Y1', 'Y1'], 
        'Z' : ['Z3', 'Z1', 'Z1', 'Z2']
    })
)
g = df2.groupby('X')
pd.pivot_table(g, values='X', rows='Y', cols='Z', margins=False, aggfunc='count')

retourneert de volgende fout:

Traceback (most recent call last): ... 
AttributeError: 'Index' object has no attribute 'index'

Hoe krijg ik een draaitabel met aantallen van unieke waardenvan één DataFrame-kolom voor twee andere kolommen?
Is er aggfuncvoor unieke telling? Moet ik np.bincount()gebruiken?

NB. Ik ben me bewust van pandas.Series.values_counts()maar ik heb een draaitabel nodig.


EDIT: de uitvoer moet zijn:

Z   Z1  Z2  Z3
Y             
Y1   1   1 NaN
Y2 NaN NaN   1

Antwoord 1, autoriteit 100%

Bedoel je zoiets?

>>> df2.pivot_table(values='X', index='Y', columns='Z', aggfunc=lambda x: len(x.unique()))
Z   Z1  Z2  Z3
Y             
Y1   1   1 NaN
Y2 NaN NaN   1

Merk op dat het gebruik van lenervan uitgaat dat je geen NA‘s in je DataFrame hebt. Je kunt x.value_counts().count()of len(x.dropna().unique())anders doen.


Antwoord 2, autoriteit 46%

Dit is een goede manier om items binnen .pivot_tablete tellen:

>>> df2.pivot_table(values='X', index=['Y','Z'], columns='X', aggfunc='count')
        X1  X2
Y   Z       
Y1  Z1   1   1
    Z2   1  NaN
Y2  Z3   1  NaN

Antwoord 3, autoriteit 31%

Sinds versie 0.16 van panda’s, is de parameter “rijen” niet nodig

Vanaf 0,23 zou de oplossing zijn:

df2.pivot_table(values='X', index='Y', columns='Z', aggfunc=pd.Series.nunique)

die terugkeert:

Z    Z1   Z2   Z3
Y                
Y1  1.0  1.0  NaN
Y2  NaN  NaN  1.0

Antwoord 4, autoriteit 6%

aggfunc=pd.Series.nuniquebiedt een duidelijk aantal. Volledige code volgt:

df2.pivot_table(values='X', rows='Y', cols='Z', aggfunc=pd.Series.nunique)

Met dank aan @hume voor deze oplossing (zie opmerking onder het geaccepteerde antwoord). Hier als antwoord toevoegen voor een betere vindbaarheid.


Antwoord 5, autoriteit 3%

U kunt een draaitabel maken voor elke afzonderlijke waarde van X. In dit geval

for xval, xgroup in g:
    ptable = pd.pivot_table(xgroup, rows='Y', cols='Z', 
        margins=False, aggfunc=numpy.size)

maakt een draaitabel voor elke waarde van X. Misschien wil je ptableindexeren met de xvalue. Met deze code krijg ik (voor X1)

    X        
Z   Z1  Z2  Z3
Y             
Y1   2   1 NaN
Y2 NaN NaN   1

Antwoord 6, autoriteit 3%

out = df2.pivot_table(values='X', index='Y', columns='Z', aggfunc=['nunique', 'count', lambda x: len(x.unique()), len])
[out]:
             nunique           count           <lambda>            len          
Z       Z1   Z2   Z3    Z1   Z2   Z3       Z1   Z2   Z3   Z1   Z2   Z3
Y                                                                     
Y1     1.0  1.0  NaN   2.0  1.0  NaN      1.0  1.0  NaN  2.0  1.0  NaN
Y2     NaN  NaN  1.0   NaN  NaN  1.0      NaN  NaN  1.0  NaN  NaN  1.0
out = df2.pivot_table(values='X', index='Y', columns='Z', aggfunc='nunique')
[out]:
Z    Z1   Z2   Z3
Y                
Y1  1.0  1.0  NaN
Y2  NaN  NaN  1.0
out = df2.pivot_table(values='X', index='Y', columns='Z', aggfunc=['nunique'])
[out]:
             nunique          
Z       Z1   Z2   Z3
Y                   
Y1     1.0  1.0  NaN
Y2     NaN  NaN  1.0

Antwoord 7

Voor de beste prestaties raad ik aan om DataFrame.drop_duplicateste volgen aggfunc='count'.

Anderen hebben gelijk dat aggfunc=pd.Series.nuniquezal werken. Dit kan echter traag zijn als het aantal index-groepen dat u heeft groot is (>1000).

Dus in plaats van (om @Javier te citeren)

df2.pivot_table('X', 'Y', 'Z', aggfunc=pd.Series.nunique)

Ik stel voor

df2.drop_duplicates(['X', 'Y', 'Z']).pivot_table('X', 'Y', 'Z', aggfunc='count')

Dit werkt omdat het garandeert dat elke subgroep (elke combinatie van ('Y', 'Z')) unieke (niet-dubbele) waarden van 'X'.


Antwoord 8

aggfunc=pd.Series.nunique
telt alleen unieke waarden voor een reeks – in dit geval telt de unieke waarden voor een kolom. Maar dit is niet echt een alternatief voor aggfunc='count'

Voor eenvoudig tellen is het beter om aggfunc=pd.Series.count

te gebruiken


Antwoord 9

Aangezien geen van de antwoorden up-to-date is met de laatste versie van Pandas, schrijf ik een andere oplossing voor dit probleem:

import pandas as pd
# Set example
df2 = (
    pd.DataFrame({
        'X' : ['X1', 'X1', 'X1', 'X1'], 
        'Y' : ['Y2', 'Y1', 'Y1', 'Y1'], 
        'Z' : ['Z3', 'Z1', 'Z1', 'Z2']
    })
)
# Pivot
pd.crosstab(index=df2['Y'], columns=df2['Z'], values=df2['X'], aggfunc=pd.Series.nunique)

die terugkeert:

Z    Z1   Z2   Z3
Y                
Y1  1.0  1.0  NaN
Y2  NaN  NaN  1.0

Other episodes