Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

458
Visualizações
¿Cómo acelerar el agg of pandas groupby bins?

Creé diferentes contenedores para cada columna y agrupé el DataFrame en función de estos.

 import pandas as pd import numpy as np np.random.seed(100) df = pd.DataFrame(np.random.randn(100, 4), columns=['a', 'b', 'c', 'value']) # for simplicity, I use the same bin here bins = np.arange(-3, 4, 0.05) df['a_bins'] = pd.cut(df['a'], bins=bins) df['b_bins'] = pd.cut(df['b'], bins=bins) df['c_bins'] = pd.cut(df['c'], bins=bins)

La salida de df.groupby(['a_bins','b_bins','c_bins']).size() indica que la longitud del grupo es 2685619.

Calcula las estadísticas de cada grupo

Luego, las estadísticas de cada grupo se calculan así:

 %%timeit df.groupby(['a_bins','b_bins','c_bins']).agg({'value':['mean']}) >>> 16.9 s ± 637 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Rendimiento esperado

  1. ¿Es posible acelerar esto?
  2. El método más rápido también debería ayudar a encontrar el valor mediante entradas de valores a, b, and c , como este:
 df.groupby(['a_bins','b_bins','c_bins']).agg({'value':['mean']}).loc[(-1.72, 0.32, 1.18)] >>> -0.252436
over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Debido a que sus contenedores son los mismos para sus 3 columnas, use codes de cat accessor:

 %timeit df.groupby([df['a_bins'].cat.codes, df['b_bins'].cat.codes, df['c_bins'].cat.codes])['value'].mean() 1.82 ms ± 27.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
over 4 years ago · Santiago Trujillo Relatório

0

Este es un buen caso de uso para scipy.stats.binned_statistic_dd . El fragmento a continuación calcula solo la estadística media, pero se admiten muchas otras estadísticas (consulte los documentos vinculados anteriormente):

 import numpy as np import pandas as pd np.random.seed(100) df = pd.DataFrame(np.random.randn(100, 4), columns=["a", "b", "c", "value"]) # for simplicity, I use the same bin here bins = np.arange(-3, 4, 0.05) df["a_bins"] = pd.cut(df["a"], bins=bins) df["b_bins"] = pd.cut(df["b"], bins=bins) df["c_bins"] = pd.cut(df["c"], bins=bins) # this takes about 35 seconds result_pandas = df.groupby(["a_bins", "b_bins", "c_bins"]).agg({"value": ["mean"]}) from scipy.stats import binned_statistic_dd # this takes about 20 ms result_scipy = binned_statistic_dd( df[["a", "b", "c"]].to_numpy(), df["value"], bins=(bins, bins, bins) ) # this is a verbose way to get a dataframe representation # for many purposes this probably will not be needed # takes about 5 seconds temp_list = [] for na, a in enumerate(result_scipy[1][0][:-1]): for nb, b in enumerate(result_scipy[1][1][:-1]): for nc, c in enumerate(result_scipy[1][2][:-1]): value = result_scipy[0][na, nb, nc] temp_list.append([a, b, c, value]) result_scipy_as_df = pd.DataFrame(temp_list, columns=list("abcx")) # check that the result is the same result_scipy_as_df["x"].describe() == result_pandas["value"]["mean"].describe()

Si está interesado en acelerar esto aún más, esta respuesta podría ser útil.

Una advertencia importante es que binned_statistic_dd usa contenedores que están cerrados a la derecha, por ejemplo, [0,1) , excepto el último (consulte las Notas en los documentos vinculados), por lo que para los identificadores de contenedores consistentes, uno tendría que usar right=False en pd.cut .

Aquí hay un ejemplo de búsqueda, tenga en cuenta que aquí la ubicación exacta del borde del contenedor se incrementa en 1 para obtener un resultado similar al de los pandas:

 aloc, bloc, cloc = -2.12, 0.23, -1.25 print(result_pandas.loc[(aloc, bloc, cloc)]) print(result_scipy.statistic[ np.digitize(aloc, result_scipy.bin_edges[0][1:]), np.digitize(bloc, result_scipy.bin_edges[1][1:]), np.digitize(cloc, result_scipy.bin_edges[2][1:]), ])
over 4 years ago · Santiago Trujillo Relatório

0

Una solución sencilla alternativa, basada en convtools , que puede procesar el flujo de entrada de datos y no requiere que los datos de entrada quepan en la memoria:

 import numpy as np import pandas as pd from convtools import conversion as c def c_bin(left, right, bin_size): return c.if_( c.or_(c.this < left, c.this > right), None, ((c.this - left) // bin_size).pipe( (c.this * bin_size + left, (c.this + 1) * bin_size + left) ), ) to_binned = c_bin(-3, 4, 0.05) to_interval = c.if_(c.this, c.apply_func(pd.Interval, c.this, {}), None) a_bins = c.item(0).pipe(to_binned) b_bins = c.item(1).pipe(to_binned) c_bins = c.item(2).pipe(to_binned) converter = ( c.group_by(a_bins, b_bins, c_bins) .aggregate( { "a_bins": a_bins.pipe(to_interval), "b_bins": b_bins.pipe(to_interval), "c_bins": c_bins.pipe(to_interval), "value_mean": c.ReduceFuncs.Average(c.item(3)), } ) .gen_converter() ) np.random.seed(100) data = np.random.randn(100, 4) df = pd.DataFrame(converter(data)).set_index(["a_bins", "b_bins", "c_bins"]) df.loc[(-1.72, 0.32, 1.18)]

Horarios:

 In [44]: %timeit converter(data) 438 µs ± 1.59 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) # passing back to pandas, timing the end-to-end thing: In [43]: %timeit pd.DataFrame(converter(data)).set_index(["a_bins", "b_bins", "c_bins"]).loc[(-1.72, 0.32, 1.18)] 2.37 ms ± 14.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

JFYI: salida acortada del converter(data) :

 [ ..., {'a_bins': Interval(-0.44999999999999973, -0.3999999999999999, closed='right'), 'b_bins': Interval(0.7000000000000002, 0.75, closed='right'), 'c_bins': Interval(-0.19999999999999973, -0.1499999999999999, closed='right'), 'value_mean': -0.08605564337254189}, {'a_bins': Interval(-0.34999999999999964, -0.2999999999999998, closed='right'), 'b_bins': Interval(-0.1499999999999999, -0.09999999999999964, closed='right'), 'c_bins': Interval(0.050000000000000266, 0.10000000000000009, closed='right'), 'value_mean': 0.18971879197958597}, {'a_bins': Interval(-2.05, -2.0, closed='right'), 'b_bins': Interval(0.75, 0.8000000000000003, closed='right'), 'c_bins': Interval(-0.25, -0.19999999999999973, closed='right'), 'value_mean': -1.1844114274105708}]
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda