web-dev-qa-db-fra.com

Pandas convertit dataframe en tableau de tuples

J'ai manipulé des données en utilisant pandas) et je souhaite maintenant effectuer une sauvegarde en différé dans la base de données. Cela nécessite de convertir le cadre de données en un tableau de tuples, chaque nuplet correspondant à un "ligne" du cadre de données.

Mon DataFrame ressemble à quelque chose comme:

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 

Je veux le convertir en un tableau de tuples comme:

[(datetime.date(2012,2,17),24.75,25.03),
(datetime.date(2012,2,16),25.00,25.07),
...etc. ]

Toute suggestion sur la façon dont je peux efficacement faire cela?

101
enrishi

Que diriez-vous:

subset = data_set[['data_date', 'data_1', 'data_2']]
tuples = [Tuple(x) for x in subset.values]
162
Wes McKinney
list(data_set.itertuples(index=False))

À partir de 17.1, ce qui précède renverra un liste des nommés .

Si vous voulez une liste de n-uplets ordinaires, passez name=None comme argument:

list(data_set.itertuples(index=False, name=None))
99
ksindi

Une manière générique:

[Tuple(x) for x in data_set.to_records(index=False)]
42

Motivation
De nombreux ensembles de données sont suffisamment volumineux pour nous obliger à nous préoccuper de la vitesse/efficacité. Je propose donc cette solution dans cet esprit. Cela arrive aussi d'être succinct.

Par souci de comparaison, supprimons la colonne index

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

Solution
Je propose l’utilisation de Zip et une compréhension

list(Zip(*[df[c].values.tolist() for c in 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)]

Il se trouve que vous devez également faire preuve de souplesse si vous souhaitez traiter un sous-ensemble spécifique de colonnes. Nous supposerons que les colonnes que nous avons déjà affichées sont le sous-ensemble que nous voulons.

list(Zip(*[df[c].values.tolist() for c in ['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)]

Tous les résultats suivants produisent les mêmes résultats

  • [Tuple(x) for x in df.values]
  • df.to_records(index=False).tolist()
  • list(map(Tuple,df.values))
  • list(map(Tuple, df.itertuples(index=False)))

Qu'est-ce qui est plus rapide?
Zip et la compréhension est beaucoup plus rapide

%timeit [Tuple(x) for x in df.values]
%timeit list(map(Tuple, df.itertuples(index=False)))
%timeit df.to_records(index=False).tolist()
%timeit list(map(Tuple,df.values))
%timeit list(Zip(*[df[c].values.tolist() for c in df]))

petites données

10000 loops, best of 3: 55.7 µs per loop
1000 loops, best of 3: 596 µs per loop
10000 loops, best of 3: 38.2 µs per loop
10000 loops, best of 3: 54.3 µs per loop
100000 loops, best of 3: 12.9 µs per loop

données volumineuses

10 loops, best of 3: 58.8 ms per loop
10 loops, best of 3: 43.9 ms per loop
10 loops, best of 3: 29.3 ms per loop
10 loops, best of 3: 53.7 ms per loop
100 loops, best of 3: 6.09 ms per loop
17
piRSquared

Voici une approche vectorisée (en supposant que le dataframe, data_set à définir à la place df à la place) qui renvoie un list sur tuples comme indiqué:

>>> df.set_index(['data_date'])[['data_1', 'data_2']].to_records().tolist()

produit:

[(datetime.datetime(2012, 2, 17, 0, 0), 24.75, 25.03),
 (datetime.datetime(2012, 2, 16, 0, 0), 25.0, 25.07),
 (datetime.datetime(2012, 2, 15, 0, 0), 24.99, 25.15),
 (datetime.datetime(2012, 2, 14, 0, 0), 24.68, 25.05),
 (datetime.datetime(2012, 2, 13, 0, 0), 24.62, 24.77),
 (datetime.datetime(2012, 2, 10, 0, 0), 24.38, 24.61)]

L’idée de définir la colonne date/heure comme axe d’index est utile pour la conversion de la valeur Timestamp en sa valeur correspondante datetime.datetime équivalent de format en utilisant le convert_datetime64 argument dans DF.to_records qui le fait pour un DateTimeIndex dataframe.

Ceci retourne un recarray qui pourrait ensuite être retourné un list en utilisant .tolist


Une solution plus généralisée en fonction du cas d'utilisation serait:

df.to_records().tolist()                              # Supply index=False to exclude index
9
Nickil Maveli

Cette réponse n’ajoute aucune réponse qui n’a pas encore été discutée, mais voici quelques résultats rapides. Je pense que cela devrait résoudre les questions soulevées dans les commentaires. Ils ressemblent tous à O (n) , en fonction de ces trois valeurs.

TL; DR: tuples = list(df.itertuples(index=False, name=None)) et tuples = list(Zip(*[df[c].values.tolist() for c in df])) sont liés pour le plus rapide.

J'ai fait un test de vitesse rapide sur les résultats pour trois suggestions ici:

  1. La réponse Zip de @pirsquared: tuples = list(Zip(*[df[c].values.tolist() for c in df]))
  2. La réponse acceptée de @ wes-mckinney: tuples = [Tuple(x) for x in df.values]
  3. Les itertuples répondent de @ksindi avec la suggestion name=None De @Axel: tuples = list(df.itertuples(index=False, name=None))
from numpy import random
import pandas as pd


def create_random_df(n):
    return pd.DataFrame({"A": random.randint(n, size=n), "B": random.randint(n, size=n)})

Petite taille:

df = create_random_df(10000)
%timeit tuples = list(Zip(*[df[c].values.tolist() for c in df]))
%timeit tuples = [Tuple(x) for x in df.values]
%timeit tuples = list(df.itertuples(index=False, name=None))

Donne:

1.66 ms ± 200 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
15.5 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.74 ms ± 75.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Plus grande:

df = create_random_df(1000000)
%timeit tuples = list(Zip(*[df[c].values.tolist() for c in df]))
%timeit tuples = [Tuple(x) for x in df.values]
%timeit tuples = list(df.itertuples(index=False, name=None))

Donne:

202 ms ± 5.91 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
1.52 s ± 98.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
209 ms ± 11.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Autant de patience que j'ai:

df = create_random_df(10000000)
%timeit tuples = list(Zip(*[df[c].values.tolist() for c in df]))
%timeit tuples = [Tuple(x) for x in df.values]
%timeit tuples = list(df.itertuples(index=False, name=None))

Donne:

1.78 s ± 118 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
15.4 s ± 222 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
1.68 s ± 96.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

La version Zip et la version itertuples se trouvent dans les intervalles de confiance. Je soupçonne qu'ils font la même chose sous le capot.

Ces tests de vitesse sont probablement sans importance cependant. Pousser les limites de la mémoire de mon ordinateur ne prend pas beaucoup de temps, et vous vraiment ne devriez pas le faire sur un grand ensemble de données. Travailler avec ces tuples après cela finira par être vraiment inefficace. Il est peu probable que votre code soit un goulet d'étranglement majeur, il vous suffit donc de vous en tenir à la version la plus lisible.

6
T.C. Proctor

Le moyen le plus efficace et le plus simple:

list(data_set.to_records())

Vous pouvez filtrer les colonnes dont vous avez besoin avant cet appel.

4
Gustavo Gonçalves

Plus façon pythonique:

df = data_set[['data_date', 'data_1', 'data_2']]
map(Tuple,df.values)
2
Ankur Panwar
#try this one:

tuples = list(Zip(data_set["data_date"], data_set["data_1"],data_set["data_2"]))
print (tuples)
2
Alsphere