Pandas Dataframe: Mittelwerte über mehrere Spalten berechnen??

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Katharina
User
Beiträge: 7
Registriert: Freitag 31. August 2018, 19:27

Hallo,

hoffe ihr könnt mir bei folgenden Problem weiterhelfen ...

Ich habe die folgende Liste und das folgende Dataframe:

Code: Alles auswählen

z_Liste = [['z_0101', 'z_0102'], ['z_0201', 'z_0202']]
z_data = {'z_0101': [80, 100, 60],
        'z_0102': [80, 60, 80],
        'z_0201': [None, 100, 80],
        'z_0202': [60, 80, None]}
df = pd.DataFrame(z_data)
Und nun möchte ich gerne die Mittelwerte über alle z_01xx (Mittelwert über alle Werte von z_0101 und z_0102) und alle z_02xx (Mittelwert über alle Werte von z_0201 und z_0202) Spalten berechnen, wobei die Werte letztendlich wieder in einem neuen Dataframe gespeichert werden sollen, d.h. ungefähr so:

Code: Alles auswählen

d_data = {'01':[76.66666667], '02':[80]}
mw = pd.DataFrame(d_data)
Vielen Dank für eure Hilfe! LG Katharina
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

vielleicht etwas umständlich aber läuft

Code: Alles auswählen

column_means = [df[value].mean() for value in df.columns.values]
column_names = list(df.columns)

d_data = {}
d_cnt = {}

for key, value in zip(column_names, column_means):
    try:
        d_data[key[2:4]][0] += value
        d_cnt[key[2:4]] += 1
    except:
        d_data[key[2:4]] = [value]
        d_cnt[key[2:4]] = 1

for key in d_data:
    d_data[key][0] /= d_cnt[key]

mw = pd.DataFrame(d_data)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Lösung ohne Pandas, funktioniert ab Python 3.4:

Code: Alles auswählen

>>> import statistics
>>> z_Liste = [['z_0101', 'z_0102'], ['z_0201', 'z_0202']]
>>>z_data = {'z_0101': [80, 100, 60],
...   'z_0102': [80, 60, 80],
...   'z_0201': [None, 100, 80],
...   'z_0202': [60, 80, None]}
...
>>> for group in z_Liste:
...     data = []
...     for k, v in z_data.items():
...         if k in group:
...             data.extend(v)
...     mean_value = statistics.mean([x for x in data if x])
...     print('Mean for group {}: {}'.format(group, mean_value))
... 
Mean for group ['z_0101', 'z_0102']: 76.66666666666667
Mean for group ['z_0201', 'z_0202']: 80
Das Problem mit Pandas ist IMHO, dass Pandas nicht so ohne weiteres einen Mittelwert über alle Werte in mehrere Spalten bilden kann. Jedenfalls habe ich dazu nichts gefunden.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13073
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@noisefloor: Aber `numpy` kann das, und wenn man `pandas` hat, ist `numpy` ja auch schon installiert.

Code: Alles auswählen

    data = {
        'z_0101': [80, 100, 60],
        'z_0102': [80, 60, 80],
        'z_0201': [None, 100, 80],
        'z_0202': [60, 80, None],
    }
    z_data = pd.DataFrame(data)
    averages = {
        group_key: np.nanmean(z_data[columns_index].values)
        for group_key, columns_index
        in z_data.columns.groupby(z_data.columns.str[2:4]).items()
    }
    print(averages)
Ausgabe: {'01': 76.66666666666667, '02': 80.0}
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Hmm, wo hast du denn geschaut?
https://pandas.pydata.org/pandas-docs/s ... .mean.html

Für obigen Dataframe df die mean pro Spalte und als letzte Row anhängen

Code: Alles auswählen

df = df.append(df.mean(), ignore_index=True)

Code: Alles auswählen

	z_0101	 z_0102	 z_0201	 z_0202
0	80.0	80.000000	NaN	60.0
1	100.0	60.000000	100.0	80.0
2	60.0	80.000000	80.0	NaN
3	80.0	73.333333	90.0	70.0
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13073
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Okay, noch ein bisschen kürzer:

Code: Alles auswählen

    data = {
        'z_0101': [80, 100, 60],
        'z_0102': [80, 60, 80],
        'z_0201': [None, 100, 80],
        'z_0202': [60, 80, None],
    }
    z_data = pd.DataFrame(data)
    averages = (
        z_data.groupby(z_data.columns.str[2:4], axis=1)
            .apply(lambda x: np.nanmean(x.values))
    )
    print(averages)
@ThomasL: Und wie berechnet man damit jetzt den durchschnitt von allen Werten in zwei Spalten. Also nicht für jede Spalte einzeln, sondern für alle werte aus *beiden* Spalten *zusammen*. Katharina hat ja das gewünschte Ergebnis im Beitrag – das sehe ich bei Deinem Beispiel noch nicht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

@blackjack deine Lösung ist sehr elegant, thumb_up.

Edit: siehe ersten Code, letzteres Beispiel war eine Antwort auf noisefloor´s imho,
beim nochmaligen Lesen glaube ich jetzt zu wissen, wie er es gemeint hat, (deine Frage) anders als ich es zuerst verstanden habe (df.mean() über alle Spalten geht nicht)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@ThomasL:
Hmm, wo hast du denn geschaut?
Genau da, an der Stelle. Aber das liefert ja keine Lösung auf die Frage des TE, wie du inzwischen selber festgestellt hast.

@Katharina: brauchst du Pandas wirklich und dachtest du "nur", dass das mit Pandas einfacher ist?

Gruß, noisefloor
Katharina
User
Beiträge: 7
Registriert: Freitag 31. August 2018, 19:27

Hallo,

vielen lieben Dank an alle für eure Hilfe und die tollen Rückmeldungen!
@noisefloor: Ich habe einen gesamten Datensatz auszuwerten und nach meinen Recherchen hat sich für alle bisherigen Berechnungen Pandas und DataFrames angeboten, daher diese spezielle Anforderung ...

Besonders die Rückmeldungen von _blackjack_ haben mich nun bis zu einem gewissen Grad gut weitergebracht, leider stehe ich bei einem gewissen Punkt aber schon wieder an ... ich schaffe es leider nicht z.B. den Code von _blackjack_ so zu manipulieren, dass ich auch gruppierte Ergebnisse herausbekommen kann, soll heißen:

Meine Daten haben ca. diese Form:

Code: Alles auswählen

z_Liste = [['z_0101', 'z_0102'], ['z_0201', 'z_0202']]
data = {'gesamt': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2],
'name': ['Eva', 'Eva', 'Otto', 'Otto', 'Otto', 'Eva', 'Eva', 'Eva', 'Otto', 'Otto', 'Otto', 'Otto'],
'z_0101': [80, 40, None, 80, 100, 60, 20, 60, None, 80, 100, 60],
'z_0102': [100, 60, 20, 100, 80, 80, None, 80, 20, 100, 80, 80],
'z_0201': [60, 20, 0, 60, 80, 40, 0, 40, 0, 60, 80, 40],
'z_0202': [60, 60, 80, 100, 100, 0, 20, None, 40, 100, 60, 80]}
z_data = pd.DataFrame(data)
... und das Ergebnis soll sein:

Code: Alles auswählen

d_data = {'gesamt': [1, 1, 2, 2], 'name': ['Eva', 'Otto', 'Eva', 'Otto'], 'z_01': [70.0, 76.0, 60.0, 74.29], 'z_02': [50.0, 70.0, 20.0, 57.5]}
output = pd.DataFrame(d_data)
Es geht noch immer um das Berechnen der Mittelwerte über alle z_01xx (Mittelwert über alle Werte von z_0101 und z_0102) und alle z_02xx (Mittelwert über alle Werte von z_0201 und z_0202) Spalten aber jetzt zusätzlich noch gruppiert ...

Wie gesagt, ich schaffe es leider nicht den Code so zu adaptieren, dass ich das oben dargelegte Ergebnis herausbekomme ...

Ich bin weiterhin für eure Hilfestellungen und Ideen sehr dankbar!

GLG Katharina
Antworten