binning a dataframe in pandas in Python
Podano następujący dataframe w Pandzie:
import numpy as np
df = pandas.DataFrame({"a": np.random.random(100), "b": np.random.random(100), "id": np.arange(100)})
Gdzie id
jest identyfikatorem dla każdego punktu składającego się z wartości a
i b
, W Jaki Sposób mogę binować a
i b
do określonego zbioru pojemników (tak, że mogę następnie przyjąć medianę/średnią wartość a
i b
w każdym pojemniku)? df
może mieć NaN
wartości dla a
lub b
(lub obu) dla dowolnego wiersza w df
. dzięki.
Oto lepszy przykład użycia rozwiązania Joe Kingtona z bardziej realistycznym df. The thing I ' m unsure o tym, jak uzyskać dostęp do df.elementy b dla każdego df.Grupa poniżej:
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?
# ...
4 answers
Może być bardziej efektywny sposób( mam przeczucie pandas.crosstab
przydałby się tutaj), ale oto jak bym to zrobił:
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]))
Edit: jako, że OP prosił specjalnie o środki b
binowane przez wartości w a
, po prostu zrób
groups.mean().b
Jeśli chcesz, aby indeks wyglądał ładniej (np. wyświetlał interwały jako indeks), tak jak w przykładzie @bdiamante, użyj pandas.cut
zamiast numpy.digitize
. (Wyrazy uznania dla bidamante. Nie wiedziałem, że istnieje.)
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
To wyniki w:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-06 17:14:45
Nie jestem w 100% pewien, czy to jest to, czego szukasz, ale oto, co myślę, że dochodzisz do:
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
Oczywiście, Nie wiem, jakie kosze miałeś na myśli, więc będziesz musiał wymienić Moje na swoje okoliczności.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-05 20:42:58
Odpowiedź Joe Kingtona była bardzo pomocna, jednak zauważyłem, że nie binuje wszystkich danych. W rzeczywistości zostawia wiersz z = a.min (). Sumując groups.size()
dał 99 zamiast 100.
Aby zagwarantować, że wszystkie dane są binowane, po prostu podaj liczbę pojemników do cut (), A Ta funkcja automatycznie ustawi pierwszy [ostatni] pojemnik o 0,1%, aby upewnić się, że wszystkie dane są dołączone.
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)
W tym przypadku, sumowanie grup.rozmiar () dał 100.
Wiem, że to wybredny punkt dla ten konkretny problem, ale dla podobnego problemu, który próbowałem rozwiązać, było kluczowe, aby uzyskać poprawną odpowiedź.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-16 02:26:51
Jeśli nie musisz trzymać się pandas
grupowania, możesz użyć 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))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-30 10:46:25