Pandas convierte el marco de datos en una matriz de tuplas
He manipulado algunos datos usando pandas y ahora quiero realizar un guardado por lotes en la base de datos. Esto requiere que convierta el marco de datos en una matriz de tuplas, donde cada tupla corresponde a una "fila" del marco de datos.
Mi DataFrame se parece a:
In [182]: data_set
Out[182]:
index data_date data_1 data_2
0 14303 2012-02-17 24.75 25.03
1 12009 2012-02-16 25.00 25.07
2 11830 2012-02-15 24.99 25.15
3 6274 2012-02-14 24.68 25.05
4 2302 2012-02-13 24.62 24.77
5 14085 2012-02-10 24.38 24.61
Quiero convertirlo en una serie de tuplas como:
[(datetime.date(2012,2,17),24.75,25.03),
(datetime.date(2012,2,16),25.00,25.07),
...etc. ]
¿Alguna sugerencia sobre cómo puedo hacer esto de manera eficiente?
list(data_set.itertuples(index=False))
A partir de 17.1, lo anterior devolverá una lista de tuplas nombradas .
Si desea una lista de tuplas ordinarias, pase name=None
como argumento:
list(data_set.itertuples(index=False, name=None))
Qué tal si:
subset = data_set[['data_date', 'data_1', 'data_2']]
tuples = [tuple(x) for x in subset.to_numpy()]
para pandas < 0,24 uso
tuples = [tuple(x) for x in subset.values]
Motivación
Muchos conjuntos de datos son lo suficientemente grandes como para que debamos preocuparnos por la velocidad y la eficiencia. Por eso ofrezco esta solución con ese espíritu. Resulta que también es conciso.
A modo de comparación, dejemos de lado la index
columna.
df = data_set.drop('index', 1)
Solución
Propondré el uso de zip
ymap
list(zip(*map(df.get, df)))
[('2012-02-17', 24.75, 25.03),
('2012-02-16', 25.0, 25.07),
('2012-02-15', 24.99, 25.15),
('2012-02-14', 24.68, 25.05),
('2012-02-13', 24.62, 24.77),
('2012-02-10', 24.38, 24.61)]
También es flexible si quisiéramos trabajar con un subconjunto específico de columnas. Asumiremos que las columnas que ya hemos mostrado son el subconjunto que queremos.
list(zip(*map(df.get, ['data_date', 'data_1', 'data_2'])))
[('2012-02-17', 24.75, 25.03),
('2012-02-16', 25.0, 25.07),
('2012-02-15', 24.99, 25.15),
('2012-02-14', 24.68, 25.05),
('2012-02-13', 24.62, 24.77),
('2012-02-10', 24.38, 24.61)]
¿Qué es más rápido?
El resultado de giro records
es el más rápido seguido de asintóticamente convergente zipmap
yiter_tuples
Usaré una biblioteca simple_benchmarks
que obtuve de esta publicación.
from simple_benchmark import BenchmarkBuilder
b = BenchmarkBuilder()
import pandas as pd
import numpy as np
def tuple_comp(df): return [tuple(x) for x in df.to_numpy()]
def iter_namedtuples(df): return list(df.itertuples(index=False))
def iter_tuples(df): return list(df.itertuples(index=False, name=None))
def records(df): return df.to_records(index=False).tolist()
def zipmap(df): return list(zip(*map(df.get, df)))
funcs = [tuple_comp, iter_namedtuples, iter_tuples, records, zipmap]
for func in funcs:
b.add_function()(func)
def creator(n):
return pd.DataFrame({"A": random.randint(n, size=n), "B": random.randint(n, size=n)})
@b.add_arguments('Rows in DataFrame')
def argument_provider():
for n in (10 ** (np.arange(4, 11) / 2)).astype(int):
yield n, creator(n)
r = b.run()
Comprueba los resultados
r.to_pandas_dataframe().pipe(lambda d: d.div(d.min(1), 0))
tuple_comp iter_namedtuples iter_tuples records zipmap
100 2.905662 6.626308 3.450741 1.469471 1.000000
316 4.612692 4.814433 2.375874 1.096352 1.000000
1000 6.513121 4.106426 1.958293 1.000000 1.316303
3162 8.446138 4.082161 1.808339 1.000000 1.533605
10000 8.424483 3.621461 1.651831 1.000000 1.558592
31622 7.813803 3.386592 1.586483 1.000000 1.515478
100000 7.050572 3.162426 1.499977 1.000000 1.480131
r.plot()