Manipulowałem niektórymi danymi za pomocą pand, a teraz chcę wykonać zbiorczy zapis z powrotem do bazy danych. Wymaga to ode mnie przekształcenia ramki danych w tablicę krotek, z których każda odpowiada „wierszowi” ramki danych.
Moja DataFrame wygląda mniej więcej tak:
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
Chcę przekonwertować go na tablicę krotek, takich jak:
[(datetime.date(2012,2,17),24.75,25.03),
(datetime.date(2012,2,16),25.00,25.07),
...etc. ]
Jakieś sugestie, jak mogę to skutecznie zrobić?
list(df.itertuples(index=False, name=None))
df.to_records(index=False)
i lista dyktowanych:df.to_dict('records')
Odpowiedzi:
Co powiesz na:
subset = data_set[['data_date', 'data_1', 'data_2']] tuples = [tuple(x) for x in subset.to_numpy()]
dla pand <0,24 użyj
tuples = [tuple(x) for x in subset.values]
źródło
.itertuples
, które będzie bardziej wydajne niż pobieranie wartości jako tablicy i umieszczanie ich w krotce.list(data_set.itertuples(index=False))
Od 17.1 powyższe zwróci listę nazwanych krotek .
Jeśli chcesz listę zwykłych krotek, podaj
name=None
jako argument:list(data_set.itertuples(index=False, name=None))
źródło
tuple
s w swoimzip
iteratorze (zamiastnamedtuple
s), zadzwoń:data_set.itertuples(index=False, name=None)
itertuples
jest powolny . Unikaj, jeśli to możliwe. Dla pętli (jak pokazano akceptowaną odpowiedź) jest zwykle szybszy w tych przypadkach.Ogólny sposób:
[tuple(x) for x in data_set.to_records(index=False)]
źródło
data_set.to_records(index=False).tolist()
lepiej?Motywacja
Wiele zestawów danych jest na tyle dużych, że musimy zająć się szybkością / wydajnością. Dlatego proponuję to rozwiązanie w tym duchu. Bywa też zwięzły.
Dla porównania upuśćmy
index
kolumnędf = data_set.drop('index', 1)
Rozwiązanie
Zaproponuję użycie
zip
imap
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)]
Zdarza się również, że jest elastyczny, jeśli chcemy zajmować się określonym podzbiorem kolumn. Zakładamy, że kolumny, które już wyświetliliśmy, są podzbiorem, którego potrzebujemy.
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)]
Co to jest szybsze?
records
Najszybciej następuje wyjście, po którym następuje asymptotyczna zbieżnośćzipmap
iiter_tuples
Skorzystam z biblioteki
simple_benchmarks
, którą otrzymałem z tego postufrom 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()
Sprawdź wyniki
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ódło
Oto podejście wektoryzowane (zakładając ramkę danych, którą
data_set
należy zdefiniować jakodf
), które zwraca wartośćlist
z,tuples
jak pokazano:>>> df.set_index(['data_date'])[['data_1', 'data_2']].to_records().tolist()
produkuje:
[(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)]
Ideą ustawienia kolumny datetime jako osi indeksu jest pomoc w konwersji
Timestamp
wartości do odpowiadającego jej odpowiednikadatetime.datetime
formatu poprzez użycieconvert_datetime64
argumentu, wDF.to_records
którym robi to dlaDateTimeIndex
ramki danych.Zwraca to a,
recarray
które można następnie zmusić do zwrócenialist
using.tolist
Bardziej uogólnionym rozwiązaniem w zależności od przypadku użycia byłoby:
df.to_records().tolist() # Supply index=False to exclude index
źródło
Najbardziej wydajny i łatwy sposób:
Przed wywołaniem możesz filtrować potrzebne kolumny.
źródło
Ta odpowiedź nie dodaje żadnych odpowiedzi, które nie zostały jeszcze omówione, ale oto kilka wyników dotyczących szybkości. Myślę, że to powinno rozwiązać pytania, które pojawiły się w komentarzach. Wszystkie wyglądają, jakby były O (n) , na podstawie tych trzech wartości.
TL; DR :
tuples = list(df.itertuples(index=False, name=None))
ituples = list(zip(*[df[c].values.tolist() for c in df]))
remisują za najszybszą.Wykonałem szybki test szybkości wyników dla trzech sugestii tutaj:
tuples = list(zip(*[df[c].values.tolist() for c in df]))
tuples = [tuple(x) for x in df.values]
name=None
sugestią @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)})
Mały rozmiar:
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))
Daje:
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)
Większy:
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))
Daje:
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)
Tyle cierpliwości, ile mam:
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))
Daje:
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)
Wersja zip i wersja itertuples mieszczą się w przedziałach ufności. Podejrzewam, że robią to samo pod maską.
Te testy prędkości są jednak prawdopodobnie nieistotne. Przekraczanie granic pamięci mojego komputera nie zajmuje dużo czasu i naprawdę nie powinno się tego robić na dużym zestawie danych. Praca z tymi krotkami po wykonaniu tej czynności będzie naprawdę nieefektywna. Jest mało prawdopodobne, aby stanowił on główne wąskie gardło w kodzie, więc po prostu trzymaj się wersji, którą uważasz za najbardziej czytelną.
źródło
[*zip(*map(df.get, df))]
czasu. W każdym razie pomyślałem, że uznasz to za interesujące.Zmiana listy ramek danych na listę krotek.
df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]}) print(df) OUTPUT col1 col2 0 1 4 1 2 5 2 3 6 records = df.to_records(index=False) result = list(records) print(result) OUTPUT [(1, 4), (2, 5), (3, 6)]
źródło
#try this one: tuples = list(zip(data_set["data_date"], data_set["data_1"],data_set["data_2"])) print (tuples)
źródło
Bardziej pythonowy sposób:
df = data_set[['data_date', 'data_1', 'data_2']] map(tuple,df.values)
źródło
map()
jest notorycznie nieszablonowy.