189

我已经使用 pandas 操作了一些数据,现在我想执行批量保存回数据库。这需要我将数据帧转换为元组数组,每个元组对应于数据帧的“行”。

我的 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. ]

关于如何有效地做到这一点的任何建议?

4

10 回答 10

247

怎么样:

subset = data_set[['data_date', 'data_1', 'data_2']]
tuples = [tuple(x) for x in subset.to_numpy()]

对于熊猫 < 0.24 使用

tuples = [tuple(x) for x in subset.values]
于 2012-03-18T20:39:19.787 回答
239
list(data_set.itertuples(index=False))

从 17.1 开始,上面将返回一个namedtuples 列表

如果您想要一个普通元组的列表,请name=None作为参数传递:

list(data_set.itertuples(index=False, name=None))
于 2015-12-31T21:57:12.910 回答
47

一个通用的方法:

[tuple(x) for x in data_set.to_records(index=False)]
于 2012-12-05T19:42:50.703 回答
44

动机
许多数据集足够大,我们需要关注速度/效率。因此,我本着这种精神提供了这个解决方案。它恰好也很简洁。

为了比较,让我们删除index

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

解决方案
我建议使用zipandmap

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)]

如果我们想处理特定的列子集,它也很灵活。我们假设我们已经显示的列是我们想要的子集。

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)]

什么是更快?

Turn's outrecords是最快的,其次是渐近收敛zipmapiter_tuples

我将使用simple_benchmarks这篇文章中获得的库

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()

检查结果

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()

在此处输入图像描述

于 2017-06-04T02:33:42.000 回答
13

这是一种矢量化方法(假设数据帧,data_set改为定义为df),它返回 a listtuples如下所示:

>>> 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 列设置为索引轴的想法是通过使用用于数据帧的参数来帮助将值转换为其对应Timestampdatetime.datetime等效格式。convert_datetime64DF.to_recordsDateTimeIndex

这会返回一个recarray,然后可以返回一个listusing.tolist


根据用例,更通用的解决方案是:

df.to_records().tolist()                              # Supply index=False to exclude index
于 2016-12-20T17:07:42.703 回答
12

最有效和最简单的方法:

list(data_set.to_records())

您可以在此调用之前过滤您需要的列。

于 2019-04-12T03:22:01.480 回答
9

这个答案没有添加任何尚未讨论的答案,但这里有一些速度结果。我认为这应该可以解决评论中提出的问题。基于这三个值,所有这些看起来都是O(n) 。

TL; DRtuples = list(df.itertuples(index=False, name=None)) :并列tuples = list(zip(*[df[c].values.tolist() for c in df]))最快。

我在这里对三个建议的结果进行了快速测试:

  1. @pirsquared 的 zip 答案:tuples = list(zip(*[df[c].values.tolist() for c in df]))
  2. @wes-mckinney 接受的答案:tuples = [tuple(x) for x in df.values]
  3. 来自@ksindi 的 itertuples 回答了来自@Axel 的name=None建议: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 版本在置信区间内。我怀疑他们在幕后做同样的事情。

不过,这些速度测试可能无关紧要。突破我的计算机内存的限制并不需要大量的时间,而且你真的不应该在大型数据集上这样做。在这样做之后使用这些元组最终会变得非常低效。它不太可能成为您代码中的主要瓶颈,因此请坚持使用您认为最易读的版本。

于 2019-03-01T20:59:59.323 回答
7

将数据框列表更改为元组列表。

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)]
于 2020-04-27T07:47:10.710 回答
3
#try this one:

tuples = list(zip(data_set["data_date"], data_set["data_1"],data_set["data_2"]))
print (tuples)
于 2017-10-09T19:11:29.667 回答
2

更多pythonic方式:

df = data_set[['data_date', 'data_1', 'data_2']]
map(tuple,df.values)
于 2017-04-17T15:14:49.337 回答