Creando un Pandas DataFrame vacío y luego llenándolo

12 minutos de lectura

Avatar de usuario de Matthias Kauer
Matías Kauer

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

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

Luego agregaría valores iniciales y repasaría estos datos calculando la nueva fila de la fila anterior, digamos row[A]

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 hacerlo directamente con un DataFrame, o simplemente una mejor manera en general.

Nota: estoy usando Python 2.7.

import datetime as dt
import pandas as pd
import scipy as s

if __name__ == '__main__':
    base = dt.datetime.today().date()
    dates = [ base - dt.timedelta(days=x) for x in range(0,10) ]
    dates.sort()
    
    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)]
            
    print valdict

  • ¡Nunca haga crecer un DataFrame! Siempre es más económico agregar una lista de python y luego convertirla en un DataFrame al final, tanto en términos de memoria como de rendimiento.

    – cs95

    29 de febrero de 2020 a las 12:04

  • @cs95 ¿Qué es funcionalmente diferente entre .append en pd y agregando una lista? lo sé .appenden pandas copia todo el conjunto de datos en un nuevo objeto ´, ¿los pythons append funcionan de manera diferente?

    – Lamma

    3 de abril de 2020 a las 9:16

  • @Lamma, encuentre detalles en mi respuesta a continuación. Al agregar a df, se crea un nuevo DataFrame cada vez en la memoria en lugar de usar el existente, lo que francamente es un desperdicio.

    – cs95

    5 de junio de 2020 a las 2:38


  • append ahora está oficialmente en desuso pandas.pydata.org/docs/reference/api/…

    – rubengavidia0x

    8 de marzo a las 20:10

avatar de usuario de cs95
cs95

¡NUNCA haga crecer un DataFrame en filas!

TLDR; (Solo lee 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: Acumule datos en una lista, no en un DataFrame.

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

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

df = pd.DataFrame(data)

pd.DataFrame convierte la lista de filas (donde cada fila es un valor escalar) en un DataFrame. Si su función produce DataFrames en su lugar, llame 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 para trabajar.agregar y eliminar (si es necesario).

  3. dtypes se infieren automáticamente (en lugar de asignar object a todos ellos).

  4. A RangeIndex se crea automáticamente para sus datosen lugar de tener que tener cuidado de asignar el índice correcto a la fila que está agregando en cada iteración.

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

Agregar filas iterativamente 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, todo a la vez.

*** Actualización para pandas >= 1.4: append ahora está DESAPROBADO! ***

A partir de pandas 1.4, append ahora ha sido obsoleto! Usar pd.concat en cambio. Ver el Notas de lanzamiento



Estas opciones son horribles

append o concat dentro 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 append o concat operación que tienes. Combina esto con un bucle y tienes un operación de complejidad cuadrática.

El otro error asociado con df.append es que los usuarios tienden a olvidar agregar no es una función en el lugar, por lo que el resultado debe volver a asignarse. También tienes que preocuparte por los dtypes:

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á hacer esto para solucionarlo:

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

loc dentro de un bucle

yo también he visto loc 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.

Trama de datos vacía de NaN

Y luego, está la creación de un marco de datos de NaN 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

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

Programar estos métodos es la forma más rápida de ver cuánto difieren en términos de memoria y utilidad.

ingrese la descripción de la imagen aquí

Código de evaluación comparativa para referencia.

  • Esto está literalmente 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, todo a la vez". pandas.pydata.org/pandas-docs/version/0.21/generated/…

    – endolito

    11 de agosto de 2019 a las 0:06

  • También "Nota Vale la pena señalar que concat() (y por lo tanto append()) hace una copia completa de los datos, y que reutilizar constantemente esta función puede crear un impacto significativo en el rendimiento. Si necesita usar la operación en varios conjuntos de datos, usar una lista de comprensión". pandas.pydata.org/pandas-docs/stable/user_guide/…

    – endolito

    11 de agosto de 2019 a las 0:07

  • Entonces, ¿qué hago cuando mis datos "entran" cuando 1d enumera uno a la vez y cada uno representa una columna en un marco de datos? ¿Cómo los agrego antes de convertirlos en un marco de datos? Parece que list1.apped(list2) inserta una lista dentro de otra lista en lugar de agregar una columna. Gracias

    – Confundido

    11 de marzo de 2020 a las 19:59

  • @Confounded Ese es un problema diferente al que se preguntó aquí, pero debería estar bien asignar una columna a la vez a un marco de datos vacío. El problema surge con la adición sucesiva de filas.

    – cs95

    16 de enero de 2021 a las 7:34

  • @micstr a, b y c son valores escalares atómicos individuales en lugar de listas. Si ya tiene las listas de datos disponibles, solo llame pd.DataFrame([a_list, b_list, c_list])

    – cs95

    19 de noviembre de 2021 a las 9:45

Avatar de usuario de Andy Hayden
Andy Hayden

He aquí un par de sugerencias:

Usar date_range para 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 hacer este tipo de cálculos para los datos, use un NumPy formación:

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

  • pd.date_range() no funciona para mí. Probé con DateRange (del autocompletado de eclipse), pero eso funciona con cadenas como formato de fecha, ¿verdad? Sin embargo, el enfoque general funciona (cambié el índice a otra cosa).

    – Matthias Kauer

    15 de diciembre de 2012 a las 8:42


  • date_range es una función de fábrica para crear índices de fecha y hora y fue una nueva característica en 0.8.0, definitivamente recomendaría actualizar a la última versión estable (0.9.1) hay muchas correcciones de errores y nuevas características. 🙂

    –Andy Hayden

    15 de diciembre de 2012 a las 9:52


  • Noté que hay un error tipográfico en el ejemplo de la declaración de importación. Afirma: import datatime Debería decir: import datetime Esa puede ser la causa de su dificultad.

    usuario2899462

    20 de octubre de 2013 a las 6:17


  • En mi experiencia, crear un marco de datos del tamaño necesario lleno de NaN y luego llenarlo con valores es mucho, mucho más lento que crear un marco de datos con index X 0 dimensiones (columns = []), y adjuntando una columna en cada vuelta de un ciclo. quiero decir df[col_name] = pandas.Series([...]) en un bucle iterando a través de los nombres de las columnas. En el primer caso, no solo la asignación de memoria lleva tiempo, sino que reemplazar NaN con nuevos valores parece extremadamente lento.

    - deeenes

    3 de marzo de 2015 a las 16:33


  • @deeenes definitivamente. esta respuesta probablemente debería aclararlo: muy rara vez (si es que alguna vez) desea crear un marco de datos vacío (de NaN).

    –Andy Hayden

    3 de marzo de 2015 a las 17:33

avatar de usuario de geekidharsh
geekidharsh

Si simplemente desea crear un marco de datos vacío y llenarlo con algunos marcos de datos entrantes más tarde, 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 usar adjuntar para escribir en el newDF con datos del oldDF.

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

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

  • Tenga en cuenta que append (y de manera similar concat) copia el conjunto de datos completo en un nuevo objeto cada vez, por lo tanto, iterar y agregar puede y causará un gran impacto en el rendimiento. para más información consulte: pandas.pydata.org/pandas-docs/stable/merging.html

    – MoustafaAAtta

    18 de septiembre de 2017 a las 12:21

  • @MoustafaAAtta ¿Cuáles son las alternativas para agregar iterativamente datos al marco de datos?

    – Chico Misterio

    13 de agosto de 2018 a las 11:24

  • @MoustafaAAtta ¿Es la respuesta de Fred en esta publicación: stackoverflow.com/questions/10715965/… mejor en este punto de vista?

    – Chico Misterio

    13 de agosto de 2018 a las 11:29

  • @MoustafaAAtta, quizás pueda agregar solo filas a un marco de datos, aún creará un nuevo objeto, pero para conjuntos de datos más pequeños, podría ser útil. pandas.pydata.org/pandas-docs/stable/user_guide/…

    – geekidharsh

    28 de enero de 2020 a las 21:28

  • Tenga en cuenta que el método de agregar está oficialmente en desuso, verifique la documentación: pandas.pydata.org/docs/reference/api/…

    – rubengavidia0x

    8 de marzo a las 20:08

Avatar de usuario de Afshin Amiri
afshin amiri

Inicializar marco vacío con nombres de columna

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 desee 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 está agregando filas dentro de un bucle, tenga en cuenta 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 la cantidad de registros en el bucle.

Si planea hacer adelgazamientos dentro de un gran bucle (digamos 10M‌ registros más o menos), es mejor que use una combinación de estos dos; llene un marco de datos con iloc hasta que el tamaño sea alrededor de 1000, luego agréguelo al marco de datos original y vacíe el marco de datos temporal. Esto aumentaría su rendimiento alrededor de 10 veces.

Simplemente:

import numpy as np
import pandas as pd

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

Luego llénalo.

Avatar de usuario de sociópata
sociópata

Suponga un marco de datos con 19 filas

index=range(0,19)
index

columns=['A']
test = pd.DataFrame(index=index, columns=columns)

Manteniendo la Columna A como una constante

test['A']=10

Mantener la columna b como una variable dada por un ciclo

for x in range(0,19):
    test.loc[[x], 'b'] = pd.Series([x], index = [x])

Puede reemplazar la primera x en pd.Series([x], index = [x]) con cualquier valor

Avatar de usuario de Wojciech Moszczyński
Wojciech Moszczyński

Esta es mi forma de hacer un marco de datos dinámico a partir de varias listas con un bucle.

x = [1,2,3,4,5,6,7,8]
y = [22,12,34,22,65,24,12,11]
z = ['as','ss','wa', 'ss','er','fd','ga','mf']
names = ['Bob', 'Liz', 'chop']

un bucle

def dataF(x,y,z,names):
    res = []

    for t in zip(x,y,z):
        res.append

    return pd.DataFrame(res,columns=names)

Resultado

dataF(x,y,z,names)

ingrese la descripción de la imagen aquí

¿Ha sido útil esta solución?