python - recorrer - seleccionar columnas de un dataframe pandas
binning un marco de datos en pandas en Python (4)
La respuesta de Joe Kington fue muy útil, sin embargo, noté que no almacena todos los datos. En realidad, deja fuera la fila con a = a.min (). Resumiendo groups.size()
dio 99 en lugar de 100.
Para garantizar que todos los datos estén agrupados, solo pase el número de contenedores para cortar () y esa función rellenará automáticamente el primer [último] bin en un 0.1% para asegurar que todos los datos estén incluidos.
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)
En este caso, la suma de groups.size () dio 100.
Sé que este es un punto delicado para este problema en particular, pero para un problema similar que estaba tratando de resolver, fue crucial para obtener la respuesta correcta.
dado el siguiente marco de datos en pandas:
import numpy as np
df = pandas.DataFrame({"a": np.random.random(100), "b": np.random.random(100), "id": np.arange(100)})
donde id
es una identificación para cada punto que consta de un valor b
, ¿cómo puedo bin a
y b
en un conjunto específico de contenedores (para que luego pueda tomar el valor promedio / promedio de b
en cada contenedor)? df
puede tener valores NaN
para a
o b
(o ambos) para cualquier fila dada en df
. Gracias.
Aquí hay un mejor ejemplo usando la solución de Joe Kington con un df más realista. De lo que no estoy seguro es de cómo acceder a los elementos de df.b para cada grupo de df.a a continuación:
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?
# ...
No estoy 100% seguro de que esto es lo que estás buscando, pero esto es lo que creo que estás consiguiendo:
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
Por supuesto, no sé qué compartimientos tenías en mente, así que tendrás que cambiar el mío por tus circunstancias.
Puede haber una manera más eficiente (tengo la sensación de que pandas.crosstab
sería útil aquí), pero así es como lo haría:
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]))
Editar: Como el OP estaba preguntando específicamente por los medios de b
binned por los valores en a
, solo hazlo
groups.mean().b
Además, si desea que el índice se vea mejor (por ejemplo, muestre los intervalos como el índice), como lo hacen en el ejemplo de @ bdiamante, use pandas.cut
lugar de numpy.digitize
. (Felicitaciones a bidamante. No me di cuenta de que pandas.cut
existía).
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
Esto resulta en:
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
Si no tiene que apegarse a la agrupación de pandas
, puede usar 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))