Ответ 1
Как насчет:
subset = data_set[['data_date', 'data_1', 'data_2']]
tuples = [tuple(x) for x in subset.values]
Я манипулировал некоторыми данными с помощью pandas, и теперь я хочу выполнить пакетное сохранение обратно в базу данных. Это требует от меня преобразования данных в массив кортежей, причем каждый кортеж соответствует "строке" блока данных.
My DataFrame выглядит примерно так:
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
Я хочу преобразовать его в массив кортежей, например:
[(datetime.date(2012,2,17),24.75,25.03),
(datetime.date(2012,2,16),25.00,25.07),
...etc. ]
Любое предложение о том, как я могу эффективно это сделать?
Как насчет:
subset = data_set[['data_date', 'data_1', 'data_2']]
tuples = [tuple(x) for x in subset.values]
list(data_set.itertuples(index=False))
Начиная с 17.1, приведенный выше вернет список именованных кортежей.
Если вы хотите получить список обычных кортежей, передайте name=None
в качестве аргумента:
list(data_set.itertuples(index=False, name=None))
Общий способ:
[tuple(x) for x in data_set.to_records(index=False)]
Мотивация
Многие наборы данных достаточно велики, и мы должны заботиться о скорости и эффективности. Поэтому я предлагаю это решение в этом духе. Это также может быть кратким.
Для сравнения, оставьте столбец index
df = data_set.drop('index', 1)
Решение
Я предлагаю использовать zip
и понимание
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)]
Также бывает гибким, если мы хотим иметь дело с определенным подмножеством столбцов. Мы предположим, что столбцы, которые мы уже отобразили, - это подмножество, которое мы хотим.
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)]
Все следующие результаты дают те же результаты
[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)))
Что происходит быстрее? zip
, а понимание выполняется с большим отрывом
%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]))
небольшие данные
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
большие данные
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
Здесь представлен векторизованный подход (предполагая, что в качестве фрейма данных data_set
будет определен как df
), который возвращает list
of tuples
, как показано:
>>> df.set_index(['data_date'])[['data_1', 'data_2']].to_records().tolist()
дает:
[(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)]
Идея установки столбца datetime как оси индекса заключается в том, чтобы помочь преобразовать значение Timestamp
в соответствующий эквивалент формата datetime.datetime
, используя аргумент convert_datetime64
в DF.to_records
, который делает это для DateTimeIndex
dataframe.
Это возвращает a recarray
, который затем можно было бы сделать, чтобы вернуть a list
, используя .tolist
Более обобщенное решение в зависимости от варианта использования будет:
df.to_records().tolist() # Supply index=False to exclude index
Этот ответ не добавляет ответов, которые еще не обсуждались, но вот некоторые результаты скорости. Я думаю, что это должно решить вопросы, которые возникли в комментариях. Все они выглядят как O (n), основываясь на этих трех значениях.
TL; DR: tuples = list(df.itertuples(index=False, name=None))
и tuples = list(zip(*[df[c].values.tolist() for c in df]))
связаны для самый быстрый.
Я сделал быстрый тест скорости на результаты для трех предложений здесь:
tuples = list(zip(*[df[c].values.tolist() for c in df]))
tuples = [tuple(x) for x in df.values]
name=None
от @Axel: tuples 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)})
Маленький размер:
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))
дает:
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)
Изображение большего размера:
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))
дает:
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)
Столько терпения, сколько у меня есть:
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))
дает:
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)
Версия zip и версия itertuples находятся в пределах доверительных интервалов друг друга. Я подозреваю, что они делают то же самое под капотом.
Эти тесты скорости, вероятно, не имеют значения, хотя. Расширение памяти моего компьютера не занимает много времени, и вам действительно не следует делать это на большом наборе данных. Работа с этими кортежами после этого может оказаться действительно неэффективной. Вряд ли это будет основным узким местом в вашем коде, поэтому просто придерживайтесь версии, которую вы считаете наиболее читаемой.
Больше pythonic way:
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)
Самый эффективный и простой способ:
list(data_set.to_records())
Вы можете отфильтровать нужные вам столбцы перед этим вызовом.