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
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:
-
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.
-
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).
-
dtypes
se infieren automáticamente (en lugar de asignarobject
a todos ellos). -
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 append
y 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.
-
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
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 NaN
s) 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
X0
dimensiones (columns = []
), y adjuntando una columna en cada vuelta de un ciclo. quiero decirdf[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
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 similarconcat
) 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
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.
-
Y para la matriz inicializada NaN equivalente, use el controlador de dispositivo que escribí!
– Nicolás Blanco
9 de febrero a las 21:33
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
-
Y para la matriz inicializada NaN equivalente, use el controlador de dispositivo que escribí!
– Nicolás Blanco
9 de febrero a las 21:33
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)
¡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é.append
en 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