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?
Que diriez-vous:
subset = data_set[['data_date', 'data_1', 'data_2']]
tuples = [Tuple(x) for x in subset.values]
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))
Une manière générique:
[Tuple(x) for x in data_set.to_records(index=False)]
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
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
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:
tuples = list(Zip(*[df[c].values.tolist() for c in df]))
tuples = [Tuple(x) for x in df.values]
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.
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.
Plus façon pythonique:
df = data_set[['data_date', 'data_1', 'data_2']]
map(Tuple,df.values)
#try this one:
tuples = list(Zip(data_set["data_date"], data_set["data_1"],data_set["data_2"]))
print (tuples)