我已经使用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

我想将它转换为元组数组,如:

1

2

3[(datetime.date(2012,2,17),24.75,25.03),

(datetime.date(2012,2,16),25.00,25.07),

...etc. ]

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

对于那些在2017年以上得到这个答案的人来说,下面有一个新的惯用解决方案。 你可以使用list(df.itertuples(index=False, name=None))

当我遇到这个问题时,我正在寻找的两件事:元组列表 - df.to_records(index=False)和一个dicts列表:df.to_dict('records')

怎么样:

1

2subset = data_set[['data_date', 'data_1', 'data_2']]

tuples = [tuple(x) for x in subset.values]

非常感谢Wes,比我提出的解决方案更清洁。对熊猫的一般工作很棒,我刚刚开始摸索表面,但它看起来很棒。

请参阅@ ksindi下面的答案,使用.itertuples,这比将值作为数组并将它们转换为元组更有效。

稍微清晰一点:元组= map(元组,subset.values)

1list(data_set.itertuples(index=False))

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

如果需要普通元组列表,请将name=None作为参数传递:

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

这应该是公认的答案恕我直言(现在存在专用功能)。顺便说一句,如果你想在zip迭代器(而不是namedtuple s)中使用普通的tuple,那么调用:data_set.itertuples(index=False, name=None)

实际上,它不应该。 itertuples很慢。尽可能避免。对于循环(如接受的答案所示),在这些情况下通常更快。

@coldspeed我从链接问题得到的教训是,迭代很慢,因为转换为元组通常比矢量化/ cython操作慢。鉴于问题是要求转换为元组,我们是否认为接受的答案更快?我做的快速测试表明itertuples版本更快。

我在这个答案中发布了我的速度测试结果

通用方式:

1[tuple(x) for x in data_set.to_records(index=False)]

动机

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

为了便于比较,我们放弃index列

1df = 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并且理解力更快

1%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

你没有做出公平的比较。您的解决方案不会比list(df.itertuples(index=False, name=None))快。这个答案只会让人迷惑。如果我是你,我会删除它。

@TedPetrou为什么不公平?没有人提出你的建议。你为什么不把它作为答案。这两个答案有助于阐明整个问题。

它就在这里:stackoverflow.com/a/34551914/3707607

你建议name = None。那没关系吗?

@piRSquared我刚试过它,name=None看起来确实有所作为。这似乎需要大约2/3的时间。我想映射一个namedtuple - > tuple转换使你测试的那个转换得慢一点。如果省略name=None,生成命名元组大约需要与您的版本一样长。

我在这个答案中发布了我的速度测试结果。

这是一个矢量化方法(假设数据帧,data_set定义为df),返回list tuples,如下所示:

1>>> 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列设置为索引轴的想法是通过利用DF.to_records中的convert_datetime64参数来帮助将Timestamp值转换为相应的datetime.datetime格式等效的DateTimeIndex。 >数据帧。

这将返回recarray,然后可以使用.tolist返回list

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

1df.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.values.tolist() for c in df]))最快并列。

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

来自@pirsquared的拉链回答:tuples = list(zip(*[df.values.tolist() for c in df]))

来自@ wes-mckinney的接受答案:tuples = [tuple(x) for x in df.values]

迭代从@ksindi回答@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

2

31.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)

大:

1

2

3

4df = 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))

得到:

1

2

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

和我一样耐心:

1

2

3

4df = 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

2

31.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版本在相互置信区间内。我怀疑他们在引擎盖下做同样的事情。

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

最有效和最简单的方法:

1list(data_set.to_records())

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

1

2

3

4#try this one:

tuples = list(zip(data_set["data_date"], data_set["data_1"],data_set["data_2"]))

print (tuples)

更多pythonic方式:

1

2df = data_set[['data_date', 'data_1', 'data_2']]

map(tuple,df.values)