Crear un Pandas DataFrame vacío y luego llenarlo

Resuelto Matthias Kauer asked hace 12 años • 8 respuestas

Estoy empezando por la documentación de pandas DataFrame aquí: Introducción a las estructuras de datos

Me gustaría llenar de forma iterativa el DataFrame con valores en un tipo de cálculo de serie temporal. Me gustaría inicializar el DataFrame con las columnas A, B y filas de marca de tiempo, todas 0 o todas NaN.

Luego agregaría valores iniciales y repasaría estos datos calculando la nueva fila a partir de la fila anterior, digamos más row[A][t] = row[A][t-1]+1o menos.

Actualmente estoy usando el código que se muestra a continuación, pero siento que es un poco feo y debe haber una manera de hacer esto directamente con un DataFrame o simplemente una mejor manera en general.

import pandas as pd
import datetime as dt
import scipy as s
base = dt.datetime.today().date()
dates = [ base - dt.timedelta(days=x) for x in range(9, -1, -1) ]

valdict = {}
symbols = ['A','B', 'C']
for symb in symbols:
    valdict[symb] = pd.Series( s.zeros(len(dates)), dates )

for thedate in dates:
    if thedate > dates[0]:
        for symb in valdict:
            valdict[symb][thedate] = 1 + valdict[symb][thedate - dt.timedelta(days=1)]
Matthias Kauer avatar Dec 09 '12 09:12 Matthias Kauer
Aceptado

¡NUNCA haga crecer un DataFrame en filas!

TLDR; (solo lea el texto en negrita)

La mayoría de las respuestas aquí le dirán cómo crear un DataFrame vacío y completarlo, pero nadie le dirá que es algo malo.

Este es mi consejo: acumule datos en una lista, no en un DataFrame.

Utilice una lista para recopilar sus datos y luego inicialice un DataFrame cuando esté listo. Funcionará un formato de lista de listas o de lista de dictadospd.DataFrame , acepta ambos.

data = []
for row in some_function_that_yields_data():
    data.append(row)

df = pd.DataFrame(data)

pd.DataFrameconvierte la lista de filas (donde cada fila es un valor escalar) en un DataFrame. Si su función produce DataFrames en su lugar, llame a pd.concat.

Ventajas de este enfoque:

  1. Siempre es más barato agregar a una lista y crear un DataFrame de una sola vez que crear un DataFrame vacío (o uno de NaN) y agregarlo una y otra vez.

  2. Las listas también ocupan menos memoria y son una estructura de datos mucho más liviana con la que trabajar , agregar y eliminar (si es necesario).

  3. dtypesse infieren automáticamente (en lugar de asignarlos objecta todos).

  4. A RangeIndexse crea automáticamente para sus datos , en lugar de tener que preocuparse de asignar el índice correcto a la fila que está agregando en cada iteración.

Si aún no estás convencido, esto también se menciona en la documentación :

Agregar filas de forma iterativa a un DataFrame puede ser más intensivo desde el punto de vista computacional que una sola concatenación. Una mejor solución es agregar esas filas a una lista y luego concatenar la lista con el DataFrame original de una vez.

pandas >= 2.0 Actualización: ¡ appendha sido eliminada!

DataFrame.appendquedó obsoleto en la versión 1.4 y se eliminó por completo de la API de pandas en la versión 2.0.

Consulte los documentos sobre desaprobaciones , así como este problema de github que originalmente propuso su desaprobación.



Estas opciones son horribles

appendo concatdentro de un bucle

Este es el mayor error que he visto en principiantes:

df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
    df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
    # or similarly,
    # df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)

La memoria se reasigna para cada appendoperación concatque tenga. Combine esto con un bucle y tendrá una operación de complejidad cuadrática .

El otro error asociado df.appendes que los usuarios tienden a olvidar que agregar no es una función local , por lo que el resultado debe asignarse nuevamente. También tienes que preocuparte por los tipos:

df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)

df.dtypes
A     object   # yuck!
B    float64
C     object
dtype: object

Tratar con columnas de objetos nunca es bueno, porque los pandas no pueden vectorizar operaciones en esas columnas. Deberá llamar al infer_objects()método para solucionarlo:

df.infer_objects().dtypes
A      int64
B    float64
C     object
dtype: object

locdentro de un bucle

También he visto locque se usa para agregar a un DataFrame que se creó vacío:

df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
    df.loc[len(df)] = [a, b, c]

Como antes, no ha asignado previamente la cantidad de memoria que necesita cada vez, por lo que la memoria vuelve a crecer cada vez que crea una nueva fila . Es tan malo como appendy aún más feo.

Marco de datos vacío de NaN

Y luego, está la creación de un DataFrame de NaN y todas las advertencias asociadas con el mismo.

df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
     A    B    C
0  NaN  NaN  NaN
1  NaN  NaN  NaN
2  NaN  NaN  NaN
3  NaN  NaN  NaN
4  NaN  NaN  NaN

Crea un DataFrame de objectcolumnas, como los demás.

df.dtypes
A    object  # you DON'T want this
B    object
C    object
dtype: object

Agregar todavía tiene todos los problemas que los métodos anteriores.

for i, (a, b, c) in enumerate(some_function_that_yields_data()):
    df.iloc[i] = [a, b, c]


La prueba está en el pudín

Cronometrar estos métodos es la forma más rápida de ver en qué se diferencian en términos de memoria y utilidad.

ingrese la descripción de la imagen aquí

Código de evaluación comparativa como referencia.

cs95 avatar Jun 25 '2019 02:06 cs95

Aquí hay un par de sugerencias:

Utilice date_rangepara el índice:

import datetime
import pandas as pd
import numpy as np

todays_date = datetime.datetime.now().date()
index = pd.date_range(todays_date-datetime.timedelta(10), periods=10, freq='D')

columns = ['A','B', 'C']

Nota: podríamos crear un DataFrame vacío (con NaNs) simplemente escribiendo:

df_ = pd.DataFrame(index=index, columns=columns)
df_ = df_.fillna(0) # With 0s rather than NaNs

Para realizar este tipo de cálculos para los datos, utilice una matriz NumPy :

data = np.array([np.arange(10)]*3).T

Por lo tanto podemos crear el DataFrame:

In [10]: df = pd.DataFrame(data, index=index, columns=columns)

In [11]: df
Out[11]:
            A  B  C
2012-11-29  0  0  0
2012-11-30  1  1  1
2012-12-01  2  2  2
2012-12-02  3  3  3
2012-12-03  4  4  4
2012-12-04  5  5  5
2012-12-05  6  6  6
2012-12-06  7  7  7
2012-12-07  8  8  8
2012-12-08  9  9  9
Andy Hayden avatar Dec 09 '2012 09:12 Andy Hayden

Si simplemente desea crear un marco de datos vacío y llenarlo con algunos marcos de datos entrantes más adelante, intente esto:

newDF = pd.DataFrame() #creates a new dataframe that's empty
newDF = newDF.append(oldDF, ignore_index = True) # ignoring index is optional
# try printing some data from newDF
print newDF.head() #again optional 

En este ejemplo, estoy usando este documento de pandas para crear un nuevo marco de datos y luego uso append para escribir en el nuevo DF con datos del antiguo DF.

Si tengo que seguir agregando nuevos datos a este nuevo DF de más de un antiguo DF, simplemente uso un bucle for para iterar sobre pandas.DataFrame.append()

Nota: append()está en desuso desde la versión 1.4.0. Usar concat().

geekidharsh avatar Jan 08 '2017 04:01 geekidharsh

Inicializar marco vacío con nombres de columnas

import pandas as pd

col_names =  ['A', 'B', 'C']
my_df  = pd.DataFrame(columns = col_names)
my_df

Agregar un nuevo registro a un marco

my_df.loc[len(my_df)] = [2, 4, 5]

También es posible que desees pasar un diccionario:

my_dic = {'A':2, 'B':4, 'C':5}
my_df.loc[len(my_df)] = my_dic 

Agregue otro marco a su marco existente

col_names =  ['A', 'B', 'C']
my_df2  = pd.DataFrame(columns = col_names)
my_df = my_df.append(my_df2)

Consideraciones de rendimiento

Si agrega filas dentro de un bucle, considere los problemas de rendimiento. Alrededor de los primeros 1000 registros, el rendimiento de "my_df.loc" es mejor, pero gradualmente se vuelve más lento al aumentar el número de registros en el bucle.

Si planea hacer cosas dentro de un bucle grande (por ejemplo, 10 millones de registros aproximadamente), es mejor que utilice una combinación de estos dos; llene un marco de datos con iloc hasta que el tamaño sea de alrededor de 1000, luego agréguelo al marco de datos original y vacíe el marco de datos temporal. Esto aumentaría su rendimiento aproximadamente 10 veces.

Afshin Amiri avatar Apr 23 '2018 05:04 Afshin Amiri

Simplemente:

import numpy as np
import pandas as pd

df=pd.DataFrame(np.zeros([rows,columns])

Luego llénalo.

razimbres avatar Oct 19 '2021 16:10 razimbres