Pandas convierte el marco de datos en una matriz de tuplas

Resuelto enrishi asked hace 12 años • 11 respuestas

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?

enrishi avatar Mar 18 '12 19:03 enrishi
Aceptado
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=Nonecomo argumento:

list(data_set.itertuples(index=False, name=None))
Kamil Sindi avatar Dec 31 '2015 21:12 Kamil Sindi

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]
Wes McKinney avatar Mar 18 '2012 20:03 Wes McKinney

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 indexcolumna.

df = data_set.drop('index', 1)

Solución
Propondré el uso de zipymap

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 recordses el más rápido seguido de asintóticamente convergente zipmapyiter_tuples

Usaré una biblioteca simple_benchmarksque 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()

ingrese la descripción de la imagen aquí

piRSquared avatar Jun 04 '2017 02:06 piRSquared