r - htmloutput - tags$img shiny
¿Por qué la tabla de datos de R es mucho más rápida que los pandas? (1)
Tengo un conjunto de datos de 12 millones de filas, con 3 columnas como identificadores únicos y otras 2 columnas con valores. Estoy tratando de hacer una tarea bastante simple:
- Grupo por los tres identificadores. Esto produce alrededor de 2.6 millones de combinaciones únicas.
- Tarea 1: calcular la mediana para la columna Val1
- Tarea 2: calcular la media para la columna Val1
dada alguna condición en Val2
Aquí están mis resultados, utilizando pandas
y data.table
(ambas versiones más recientes en este momento, en la misma máquina):
+-----------------+-----------------+------------+
| | pandas | data.table |
+-----------------+-----------------+------------+
| TASK 1 | 150 seconds | 4 seconds |
| TASK 1 + TASK 2 | doesn''t finish | 5 seconds |
+-----------------+-----------------+------------+
Creo que puedo estar haciendo algo mal con los pandas: transformar Grp1
y Grp2
en categorías no ayudó mucho, ni tampoco cambiar entre .agg
y .apply
. ¿Algunas ideas?
A continuación se muestra el código reproducible.
Generación de cuadros de datos:
import numpy as np
import pandas as pd
from collections import OrderedDict
import time
np.random.seed(123)
list1 = list(pd.util.testing.rands_array(10, 750))
list2 = list(pd.util.testing.rands_array(10, 700))
list3 = list(np.random.randint(100000,200000,5))
N = 12 * 10**6 # please make sure you have enough RAM
df = pd.DataFrame({''Grp1'': np.random.choice(list1, N, replace = True),
''Grp2'': np.random.choice(list2, N, replace = True),
''Grp3'': np.random.choice(list3, N, replace = True),
''Val1'': np.random.randint(0,100,N),
''Val2'': np.random.randint(0,10,N)})
# this works and shows there are 2,625,000 unique combinations
df_test = df.groupby([''Grp1'',''Grp2'',''Grp3'']).size()
print(df_test.shape[0]) # 2,625,000 rows
# export to feather so that same df goes into R
df.to_feather(''file.feather'')
Tarea 1 en Python:
# TASK 1: 150 seconds (sorted / not sorted doesn''t seem to matter)
df.sort_values([''Grp1'',''Grp2'',''Grp3''], inplace = True)
t0 = time.time()
df_agg1 = df.groupby([''Grp1'',''Grp2'',''Grp3'']).agg({''Val1'':[np.median]})
t1 = time.time()
print("Duration for complex: %s seconds ---" % (t1 - t0))
Tarea 1 + Tarea 2 en Python:
# TASK 1 + TASK 2: this kept running for 10 minutes to no avail
# (sorted / not sorted doesn''t seem to matter)
def f(x):
d = OrderedDict()
d[''Median_all''] = np.median(x[''Val1''])
d[''Median_lt_5''] = np.median(x[''Val1''][x[''Val2''] < 5])
return pd.Series(d)
t0 = time.time()
df_agg2 = df.groupby([''Grp1'',''Grp2'',''Grp3'']).apply(f)
t1 = time.time()
print("Duration for complex: %s seconds ---" % (t1 - t0)) # didn''t complete
Código R equivalente:
library(data.table)
library(feather)
DT = setDT(feater("file.feather"))
system.time({
DT_agg <- DT[,.(Median_all = median(Val1),
Median_lt_5 = median(Val1[Val2 < 5]) ), by = c(''Grp1'',''Grp2'',''Grp3'')]
}) # 5 seconds
No puedo reproducir tus resultados de R, arreglé el error tipográfico en el que escribiste incorrectamente, pero obtengo lo siguiente:
Error in `[.data.table`(DT, , .(Median_all = median(Val1), Median_lt_5 = median(Val1[Val2 < :
column or expression 1 of ''by'' or ''keyby'' is type NULL. Do not quote column names. Usage: DT[,sum(colC),by=list(colA,month(colB))]
En cuanto al ejemplo de Python, si desea obtener la mediana para cada grupo donde Val2 es menor que 5, primero debe filtrar, como en:
df[df.Val2 < 5].groupby([''Grp1'',''Grp2'',''Grp3''])[''Val2''].median()
Esto se completa en menos de 8 segundos en mi Macbook Pro.