2013-03-23 3 views
11

Mein Problem ist, wie man Häufigkeiten für mehrere Variablen in Pandas berechnet. Ich habe von diesem Datenrahmen:Frequenztabellen in Pandas (wie plyr in R)

d1 = pd.DataFrame({'StudentID': ["x1", "x10", "x2","x3", "x4", "x5", "x6", "x7",  "x8", "x9"], 
         'StudentGender' : ['F', 'M', 'F', 'M', 'F', 'M', 'F', 'M', 'M', 'M'], 
       'ExamenYear': ['2007','2007','2007','2008','2008','2008','2008','2009','2009','2009'], 
       'Exam': ['algebra', 'stats', 'bio', 'algebra', 'algebra', 'stats', 'stats', 'algebra', 'bio', 'bio'], 
       'Participated': ['no','yes','yes','yes','no','yes','yes','yes','yes','yes'], 
        'Passed': ['no','yes','yes','yes','no','yes','yes','yes','no','yes']}, 
        columns = ['StudentID', 'StudentGender', 'ExamenYear', 'Exam', 'Participated', 'Passed']) 

zu folgendem Ergebnis

   Participated OfWhichpassed 
ExamenYear        
2007     3    2 
2008     4    3 
2009     3    2 

(1) Eine Möglichkeit, habe ich versucht, zwei Datenrahmen zu berechnen, und bindet es

t1 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], cols = ['Participated'], aggfunc = len) 
t2 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], cols = ['Passed'], aggfunc = len) 
tx = pd.concat([t1, t2] , axis = 1) 

Res1 = tx['yes'] 

(2) Die zweite Möglichkeit besteht darin, eine Aggregationsfunktion zu verwenden.

import collections 
dg = d1.groupby('ExamenYear') 
Res2 = dg.agg({'Participated': len,'Passed': lambda x : collections.Counter(x == 'yes')[True]}) 

Res2.columns = ['Participated', 'OfWhichpassed'] 

Beide Wege sind awckward, gelinde gesagt. Wie wird das in Pandas richtig gemacht?

PS: Ich habe auch versucht value_counts statt collections.Counter konnte aber nicht

Als Referenz an die Arbeit: Vor einigen Monaten habe ich ähnliche Frage für R here und plyr konnte gefragt Hilfe

---- ------ UPDATE

Benutzer DSM ist richtig. Es gab einen Fehler im gewünschten Tabellenergebnis.

(1) Der Code für die Option ist

t1 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], aggfunc = len) 
t2 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], cols = ['Participated'], aggfunc = len) 
t3 = d1.pivot_table(values = 'StudentID', rows=['ExamenYear'], cols = ['Passed'], aggfunc = len) 

Res1 = pd.DataFrame({'All': t1, 
         'OfWhichParticipated': t2['yes'], 
        'OfWhichPassed': t3['yes']}) 

Es wird das Ergebnis produzieren

   All OfWhichParticipated OfWhichPassed 
ExamenYear           
2007   3     2    2 
2008   4     3    3 
2009   3     3    2 

(2) Für Option 2 dank Benutzer herrfz, ich herausgefunden, wie um value_count zu verwenden und der code wird

Res2 = d1.groupby('ExamenYear').agg({'StudentID': len, 
           'Participated': lambda x: x.value_counts()['yes'], 
           'Passed': lambda x: x.value_counts()['yes']}) 

Res2.columns = ['All', 'OfWgichParticipated', 'OfWhichPassed'] 

sein, die th produzieren wird e gleiche Ergebnis wie Res1

Meine Frage aber bleibt: (für einen anderen Betrieb)

Option Mit 2 wird es möglich sein, zweimal die gleiche Variable zu verwenden, kann man einen benutzerdefinierten Namen für die resultierende Variable übergeben?

---- Ein neues Update ----

Ich habe schließlich beschlossen, gelten zu verwenden, die ich verstehe, flexibler ist. Diese

+0

Ich bin mir nicht sicher, ob ich Ihre Ausgabe verstehe. Betrachtet man 2007, scheint es zwei Studenten zu geben, die teilgenommen haben = ja, aber Ihre gewünschte Ausgabe hat "3" - d. H. Alle 2007 Studenten. Möchten Sie, dass die Werte der neuen Participated-Spalte die Anzahl sind? – DSM

+0

.. Eigentlich sind deine 'Res1' und' Res2' nicht einverstanden, also bin ich mir nicht sicher, ob du dich auch dafür entschieden hast. – DSM

+0

Sie haben recht: Was ich mit 'Teilgenommen' meinte, ist eigentlich die Länge des DataFrames (und nicht Teilgenommen == ja). Macht nichts, ich denke, die zweite Lösung sieht vielversprechender aus – user1043144

Antwort

7

:

d1.groupby('ExamenYear').agg({'Participated': len, 
           'Passed': lambda x: sum(x == 'yes')}) 

sieht nicht viel mehr umständlich als die R-Lösung, IMHO.

+0

Danke. Dies ist eine Verbesserung. Gibt es eine Möglichkeit, einen benutzerdefinierten Namen an die resultierende Spalte (z. B. OfWhichpassed) zu übergeben. Anscheinend können Sie ein Tupel von benutzerdefinierten Namen an agg übergeben ('customname', 'nameoffunction'), aber wird es hier funktionieren? – user1043144

11

Ich entschied mich schließlich zu verwenden anwenden.

Ich posten, was ich kam in der Hoffnung, dass es für andere nützlich sein kann.

Von dem, was ich von Wes' Buch ‚Python für Datenanalyse‘ verstehen

  • gelten als agg flexibler ist und zu transformieren, weil Sie Ihre eigene Funktion definieren können.
  • Die einzige Anforderung ist, dass die Funktionen ein Pandas Objekt oder Skalarwert zurückgibt.
  • der inneren Mechanik: die Funktion auf jedem Stück des gruppierten Objekts abd Ergebnisse zusammengeklebt werden pandas.concat mit genannt wird
  • Man muss „hart-Code“ Struktur, die Sie am Ende
wollen

Hier ist, was ich mit

def ZahlOccurence_0(x): 
     return pd.Series({'All': len(x['StudentID']), 
         'Part': sum(x['Participated'] == 'yes'), 
         'Pass' : sum(x['Passed'] == 'yes')}) 

kam, wenn ich es laufen:

d1.groupby('ExamenYear').apply(ZahlOccurence_0) 

ich die richtigen Ergebnisse

  All Part Pass 
ExamenYear     
2007   3  2  2 
2008   4  3  3 
2009   3  3  2 

Dieser Ansatz würde mir auch erlauben, Frequenzen mit anderen Statistiken zu kombinieren

import numpy as np 
d1['testValue'] = np.random.randn(len(d1)) 

def ZahlOccurence_1(x): 
    return pd.Series({'All': len(x['StudentID']), 
     'Part': sum(x['Participated'] == 'yes'), 
     'Pass' : sum(x['Passed'] == 'yes'), 
     'test' : x['testValue'].mean()}) 


d1.groupby('ExamenYear').apply(ZahlOccurence_1) 


      All Part Pass  test 
ExamenYear       
2007   3  2  2 0.358702 
2008   4  3  3 1.004504 
2009   3  3  2 0.521511 

Ich hoffe, dass jemand anderes diese nützliche

1

finden Es gibt einen anderen Ansatz das ich gerne für ähnliche probleme verwende, benutzt es groupby und unstack:

d1 = pd.DataFrame({'StudentID': ["x1", "x10", "x2","x3", "x4", "x5", "x6", "x7",  "x8", "x9"], 
        'StudentGender' : ['F', 'M', 'F', 'M', 'F', 'M', 'F', 'M', 'M', 'M'], 
        'ExamenYear': ['2007','2007','2007','2008','2008','2008','2008','2009','2009','2009'], 
        'Exam': ['algebra', 'stats', 'bio', 'algebra', 'algebra', 'stats', 'stats', 'algebra', 'bio', 'bio'], 
        'Participated': ['no','yes','yes','yes','no','yes','yes','yes','yes','yes'], 
        'Passed': ['no','yes','yes','yes','no','yes','yes','yes','no','yes']}, 
        columns = ['StudentID', 'StudentGender', 'ExamenYear', 'Exam', 'Participated', 'Passed']) 

(dies ist nur die Rohdaten von oben)

d2 = d1.groupby("ExamenYear").Participated.value_counts().unstack(fill_value=0)['yes'] 
d3 = d1.groupby("ExamenYear").Passed.value_counts().unstack(fill_value=0)['yes'] 
d2.name = "Participated" 
d3.name = "Passed" 

pd.DataFrame(data=[d2,d3]).T 
      Participated Passed 
ExamenYear      
2007     2  2 
2008     3  3 
2009     3  2 

Diese Lösung ist etwas umständlicher als die Anwendung oben mit, aber dies ist leichter zu verstehen und zu erweitern, ich fühle mich.

6

Sie können Pandas crosstab Funktion verwenden, die standardmäßig eine Häufigkeitstabelle von zwei oder mehr Variablen berechnet. Zum Beispiel

> import pandas as pd 
> pd.crosstab(d1['ExamenYear'], d1['Passed']) 
Passed  no yes 
ExamenYear   
2007   1 2 
2008   1 3 
2009   1 2 

Verwenden Sie die margins=True Option, wenn Sie auch die Zwischensumme jeder Zeile und Spalte angezeigt werden sollen.

> pd.crosstab(d1['ExamenYear'], d1['Participated'], margins=True) 
Participated no yes All 
ExamenYear     
2007   1 2 3 
2008   1 3 4 
2009   0 3 3 
All   2 8 10