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

list(data_set.itertuples(index=False))

从17.1开始,上面的代码将返回一个命名元组列表。

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

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

下面是一个矢量化的方法(假设dataframe, data_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列设置为索引轴的想法是帮助将Timestamp值转换为相应的datetime。通过使用DF中的convert_datetime64参数来等效datetime格式。to_records用于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的out记录紧随其后的是渐进收敛的zipmap和iter_tuples

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

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


#try this one:

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

这个答案没有添加任何尚未讨论过的答案,但这里有一些速度结果。我认为这应该能解决评论中出现的问题。根据这三个值,它们看起来都是O(n)

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

我对结果做了一个快速测试,有三个建议:

@pirsquared: tuples = list(zip(*[df[c].values.tolist() for c in df])) 来自@wes-mckinney的接受答案:tuples =[在df.values中x的元组(x)] itertuples回答来自@ksindi的name=Noneitertuples(指数= False, name =))

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

不过,这些速度测试可能无关紧要。挑战计算机内存的极限并不需要花费大量的时间,而且您确实不应该在大型数据集上这样做。在此之后使用这些元组将会非常低效。它不太可能成为您代码中的主要瓶颈,所以只需坚持使用您认为最易读的版本。


最有效和最简单的方法:

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