it-swarm.com.de

Binning eines Datenrahmens in pandas in Python

gegeben den folgenden Datenrahmen in Pandas:

import numpy as np
df = pandas.DataFrame({"a": np.random.random(100), "b": np.random.random(100), "id": np.arange(100)})

wobei id eine ID für jeden Punkt ist, der aus einem a und b Wert besteht, wie kann ich a und b in einen bin angegebene Menge von Behältern (damit ich dann den Median/Durchschnittswert von a und b in jedem Behälter nehmen kann)? df hat möglicherweise NaN Werte für a oder b (oder beides) für eine bestimmte Zeile in df. Vielen Dank.

Hier ist ein besseres Beispiel für die Verwendung von Joe Kingtons Lösung mit einem realistischeren df. Ich bin mir nicht sicher, wie ich auf die df.b-Elemente für jede der folgenden df.a-Gruppen zugreifen soll:

a = np.random.random(20)
df = pandas.DataFrame({"a": a, "b": a + 10})
# bins for df.a
bins = np.linspace(0, 1, 10)
# bin df according to a
groups = df.groupby(np.digitize(df.a,bins))
# Get the mean of a in each group
print groups.mean()
## But how to get the mean of b for each group of a?
# ...
37
user248237

Es kann einen effizienteren Weg geben (ich habe das Gefühl, pandas.crosstab wäre hier nützlich), aber so würde ich es machen:

import numpy as np
import pandas

df = pandas.DataFrame({"a": np.random.random(100),
                       "b": np.random.random(100),
                       "id": np.arange(100)})

# Bin the data frame by "a" with 10 bins...
bins = np.linspace(df.a.min(), df.a.max(), 10)
groups = df.groupby(np.digitize(df.a, bins))

# Get the mean of each bin:
print groups.mean() # Also could do "groups.aggregate(np.mean)"

# Similarly, the median:
print groups.median()

# Apply some arbitrary function to aggregate binned data
print groups.aggregate(lambda x: np.mean(x[x > 0.5]))

Bearbeiten: Da das OP speziell nur nach den Mitteln von b gefragt hat, die durch die Werte in a gruppiert sind, tun Sie dies einfach

groups.mean().b

Wenn der Index besser aussehen soll (z. B. Intervalle als Index anzeigen), wie im Beispiel von @ bdiamante, verwenden Sie pandas.cut Anstatt von numpy.digitize. (Ein großes Lob an Bidamante. Ich wusste nicht, pandas.cut existierte.)

import numpy as np
import pandas

df = pandas.DataFrame({"a": np.random.random(100), 
                       "b": np.random.random(100) + 10})

# Bin the data frame by "a" with 10 bins...
bins = np.linspace(df.a.min(), df.a.max(), 10)
groups = df.groupby(pandas.cut(df.a, bins))

# Get the mean of b, binned by the values in a
print groups.mean().b

Das führt zu:

a
(0.00186, 0.111]    10.421839
(0.111, 0.22]       10.427540
(0.22, 0.33]        10.538932
(0.33, 0.439]       10.445085
(0.439, 0.548]      10.313612
(0.548, 0.658]      10.319387
(0.658, 0.767]      10.367444
(0.767, 0.876]      10.469655
(0.876, 0.986]      10.571008
Name: b
58
Joe Kington

Nicht 100% sicher, ob dies das ist, wonach Sie suchen, aber ich denke, dass Sie Folgendes erreichen:

In [144]: df = DataFrame({"a": np.random.random(100), "b": np.random.random(100), "id":   np.arange(100)})

In [145]: bins = [0, .25, .5, .75, 1]

In [146]: a_bins = df.a.groupby(cut(df.a,bins))

In [147]: b_bins = df.b.groupby(cut(df.b,bins))

In [148]: a_bins.agg([mean,median])
Out[148]:
                 mean    median
a
(0, 0.25]    0.124173  0.114613
(0.25, 0.5]  0.367703  0.358866
(0.5, 0.75]  0.624251  0.626730
(0.75, 1]    0.875395  0.869843

In [149]: b_bins.agg([mean,median])
Out[149]:
                 mean    median
b
(0, 0.25]    0.147936  0.166900
(0.25, 0.5]  0.394918  0.386729
(0.5, 0.75]  0.636111  0.655247
(0.75, 1]    0.851227  0.838805

Natürlich weiß ich nicht, welche Fächer Sie im Sinn hatten, also müssen Sie meine für Ihre Umstände austauschen.

24
bdiamante

Die Antwort von Joe Kington war sehr hilfreich, ich bemerkte jedoch, dass nicht alle Daten darin gespeichert sind. Tatsächlich wird die Zeile mit a = a.min () weggelassen. Zusammenfassend ergab groups.size() 99 statt 100.

Um sicherzustellen, dass alle Daten in Gruppen zusammengefasst sind, geben Sie einfach die Anzahl der zu schneidenden Gruppen ein (). Diese Funktion füllt die erste [letzte] Gruppe automatisch um 0,1% auf, um sicherzustellen, dass alle Daten enthalten sind.

df = pandas.DataFrame({"a": np.random.random(100), 
                    "b": np.random.random(100) + 10})

# Bin the data frame by "a" with 10 bins...
groups = df.groupby(pandas.cut(df.a, 10))

# Get the mean of b, binned by the values in a
print(groups.mean().b)

In diesem Fall ergab das Aufsummieren von groups.size () 100.

Ich weiß, dass dies ein heikler Punkt für dieses spezielle Problem ist, aber für ein ähnliches Problem, das ich zu lösen versuchte, war es entscheidend, die richtige Antwort zu erhalten.

14
Perk

Wenn Sie sich nicht an die pandas Gruppierung halten müssen, können Sie scipy.stats.binned_statistic:

from scipy.stats import binned_statistic

means = binned_statistic(df.a, df.b, bins=np.linspace(min(df.a), max(df.a), 10))
2
bio