Python 熊猫将数据帧转换为元组数组

Python 熊猫将数据帧转换为元组数组,python,pandas,Python,Pandas,我已经使用pandas操作了一些数据,现在我想执行一个批量保存回数据库。这需要我将数据帧转换为元组数组,每个元组对应于数据帧的一行 我的数据框看起来像: 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

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

我的数据框看起来像:

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.to_numpy()]
对于小于0.24的熊猫,请使用

tuples = [tuple(x) for x in subset.values]
通用方法:

[tuple(x) for x in data_set.to_records(index=False)]
从17.1开始,上述内容将返回一个

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

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

下面是一种矢量化方法(假设数据帧,
data\u set
定义为
df
),它返回
元组的
列表,如图所示:

>>> 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列设置为索引轴的想法是,通过使用
convert\u datetime64
参数,帮助将
Timestamp
值转换为相应的
datetime.datetime
格式等效值,该参数对
DateTimeIndex
数据帧执行此操作

这将返回一个
重新排列
,然后可以使用
.tolist


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

df.to_records().tolist()                              # Supply index=False to exclude index
更具python风格的方式:

df = data_set[['data_date', 'data_1', 'data_2']]
map(tuple,df.values)

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

为了便于比较,让我们删除
索引

df = data_set.drop('index', 1)
解决方案
我建议使用
zip
map

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的
记录
最快,然后是渐进收敛的
zipmap
iter\u元组

我会用我从图书馆得到的

检查结果

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


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

TL;DR
tuples=list(df.itertuples(index=False,name=None))
tuples=list(zip(*[df[c].values.tolist()表示df中的c])
并列最快

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

  • @pirsquared:
    tuples=list(zip(*[df[c].values.tolist()表示df中的c])的zip答案。
  • @wes mckinney接受的答案是:
    tuples=[tuple(x)表示df.values中的x]
  • @ksindi的itertuples答案带有@Axel:
    tuples=list的
    name=None
    建议(df.itertuples(index=False,name=None))
  • 小尺寸:

    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)
    
    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)
    
    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)
    
    较大的:

    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))
    
    给出:

    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)
    
    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)
    
    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)
    
    和我一样有耐心:

    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.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)
    
    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)
    
    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版本彼此在置信区间内。我怀疑他们在幕后也在做同样的事情


    不过,这些速度测试可能并不重要。突破我电脑内存的限制不会花费大量时间,而且你真的不应该在大数据集上这么做。这样做之后再使用这些元组将非常低效。这不太可能成为代码中的主要瓶颈,因此只需坚持使用您认为最具可读性的版本即可。

    最有效、最简单的方法:

    list(data_set.to_records())
    

    您可以在此调用之前筛选所需的列。

    将数据帧列表更改为元组列表

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

    这应该是IMHO接受的答案(现在有了专用功能)。顺便说一句,如果您希望在
    zip
    迭代器中使用正常的
    tuple
    s(而不是
    namedtuple
    s),那么调用:
    data\u set.itertuples(index=False,name=None)
    实际上,它不应该。尽可能避免@coldspeed我从链接问题中得到的教训是,itertuples很慢,因为转换为元组通常比矢量化/cython操作慢。考虑到问题是要转换为元组,我们有没有理由认为接受的答案更快?我做的快速测试表明itertuples版本更快。我在@johnDanger中发布了我的速度测试结果,这与python中eval()和globals()的概念类似。每个人都知道它们的存在。每个人都知道,您通常不应该使用这些函数,因为它们被认为是不好的形式。这里的原理是相似的,在熊猫中使用iter*家族的案例很少,这可以说是其中之一。我仍然会使用一种不同的方法(如列表比较或地图),但那就是我。对于那些在2017+中得出这个答案的人,有一个答案。您可以使用
    list(df.itertuples(index=False,name=None))
    当我遇到这个问题时,我正在寻找的两件事:元组列表-
    df.to_记录(index=False)
    和dict列表:
    df.to_dict('records')
    @MartinThoma to_records和to_dict('records')拧紧我的数据类型。已知错误,但使此解决方案毫无价值…请参阅下面@ksindi使用
    .itertuples
    的答案,这将比将值作为数组并将其转换为元组更有效。稍微干净一点的是:tuples=map(tuple,subset.values)这可以将值转换为不同的类型,对吗?我更新了我过时的帖子。我使用
    [*zip(*map(df.get,df))]
    已经有一段时间了。不管怎样,我想你会觉得很有趣的。我喜欢漂亮的情节。我猜这看起来像是O(n)。更像蟒蛇的方式:事实上恰恰相反<代码>映射()
    是出了名的非音速。不是吗