The Right Way ™ para crear un marco de datos
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.
Aquí está mi consejo: espere hasta estar seguro de tener todos los datos con los que necesita trabajar. Use una lista para recopilar sus datos, luego inicialice un DataFrame cuando esté listo.
data = []
for a, b, c in some_function_that_yields_data():
data.append([a, b, c])
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
Siempre es más barato agregar a una lista y crear un DataFrame de una vez que crear un DataFrame vacío (o uno de los NaN) y agregarlo una y otra vez. Las listas también ocupan menos memoria y son una estructura de datos mucho más liviana para trabajar , agregar y eliminar (si es necesario).
La otra ventaja de este método dtypesse infiere automáticamente (en lugar de asignarlos objecta todos).
La última ventaja es que a RangeIndexse crea automáticamente para sus datos , por lo que es una cosa menos de qué preocuparse (eche un vistazo a los pobres appendy los locmétodos a continuación, verá elementos en ambos que requieren el manejo adecuado del índice).
Cosas que NO debes hacer
appendo concatdentro de un bucle
Aquí está el error más grande que he visto de los 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 appendu concatoperación que tiene. Combine esto con un bucle y tendrá una operación de complejidad cuadrática . Desde la df.appendpágina del documento :
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.
El otro error asociado df.appendes que los usuarios tienden a olvidar que agregar no es una función in situ , por lo que el resultado debe asignarse de nuevo. También debes 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 algo bueno, porque los pandas no pueden vectorizar las operaciones en esas columnas. Deberá hacer esto para solucionarlo:
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
loc dentro de un bucle
También he visto que se locsolía 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 append, y aún más feo.
Marco de datos vacío de NaN
Y luego, está creando un DataFrame de NaNs, y todas las advertencias asociadas con él.
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 columnas de objetos, como los demás.
df.dtypes
A object # you DON'T want this
B object
C object
dtype: object
Anexar todavía tiene todos los problemas como 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
El cronometraje de estos métodos es la forma más rápida de ver cuánto difieren en términos de su memoria y utilidad.

Código de referencia para referencia.