two data concatenate columns python performance pandas concatenation processing-efficiency

python dataframe concatenate two columns



¿Por qué la concatenación de DataFrames se vuelve exponencialmente más lenta? (2)

Tengo una función que procesa un DataFrame, en gran parte para procesar datos en cubos, crear una matriz binaria de características en una columna particular usando pd.get_dummies(df[col]) .

Para evitar procesar todos mis datos usando esta función de una vez (que se queda sin memoria y hace que iPython se bloquee), he dividido el gran DataFrame en fragmentos usando:

chunks = (len(df) / 10000) + 1 df_list = np.array_split(df, chunks)

pd.get_dummies(df) creará automáticamente nuevas columnas basadas en el contenido de df[col] y es probable que estas difieran para cada df en df_list .

Después del procesamiento, estoy concatenando los DataFrames nuevamente usando:

for i, df_chunk in enumerate(df_list): print "chunk", i [x, y] = preprocess_data(df_chunk) super_x = pd.concat([super_x, x], axis=0) super_y = pd.concat([super_y, y], axis=0) print datetime.datetime.utcnow()

El tiempo de procesamiento del primer fragmento es perfectamente aceptable, sin embargo, ¡crece por fragmento! Esto no tiene que ver con preprocess_data(df_chunk) ya que no hay razón para que aumente. ¿Se produce este aumento de tiempo como resultado de la llamada a pd.concat() ?

Por favor, consulte el registro a continuación:

chunks 6 chunk 0 2016-04-08 00:22:17.728849 chunk 1 2016-04-08 00:22:42.387693 chunk 2 2016-04-08 00:23:43.124381 chunk 3 2016-04-08 00:25:30.249369 chunk 4 2016-04-08 00:28:11.922305 chunk 5 2016-04-08 00:32:00.357365

¿Hay alguna solución para acelerar esto? Tengo 2900 fragmentos para procesar, por lo que agradeceré cualquier ayuda.

¡Abierto a cualquier otra sugerencia en Python!


Cada vez que concatena, devuelve una copia de los datos.

Desea mantener una lista de sus fragmentos y luego concatenar todo como el paso final.

df_x = [] df_y = [] for i, df_chunk in enumerate(df_list): print "chunk", i [x, y] = preprocess_data(df_chunk) df_x.append(x) df_y.append(y) super_x = pd.concat(df_x, axis=0) del df_x # Free-up memory. super_y = pd.concat(df_y, axis=0) del df_y # Free-up memory.


Nunca llame a DataFrame.append o pd.concat dentro de un ciclo for. Conduce a la copia cuadrática.

pd.concat devuelve un nuevo DataFrame. Se debe asignar espacio para el nuevo DataFrame, y los datos de los antiguos DataFrames se deben copiar en el nuevo DataFrame. Considere la cantidad de copia requerida por esta línea dentro del for-loop (suponiendo que cada x tenga tamaño 1):

super_x = pd.concat([super_x, x], axis=0) | iteration | size of old super_x | size of x | copying required | | 0 | 0 | 1 | 1 | | 1 | 1 | 1 | 2 | | 2 | 2 | 1 | 3 | | ... | | | | | N-1 | N-1 | 1 | N |

1 + 2 + 3 + ... + N = N(N+1)/2 . Por lo tanto, se requieren O(N**2) copias para completar el ciclo.

Ahora considera

super_x = [] for i, df_chunk in enumerate(df_list): [x, y] = preprocess_data(df_chunk) super_x.append(x) super_x = pd.concat(super_x, axis=0)

Agregar a una lista es una operación O(1) y no requiere copia. Ahora hay una sola llamada a pd.concat después de finalizar el ciclo. Esta llamada a pd.concat requiere que se pd.concat N copias, ya que super_x contiene N DataFrames de tamaño 1. Entonces, cuando se construye de esta manera, super_x requiere O(N) copias.