Pandas 将数据框转换为元组数组
- 2025-02-28 08:23:00
- admin 原创
- 67
问题描述:
我已经使用 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. ]
关于如何有效地做到这一点,有什么建议吗?
解决方案 1:
list(data_set.itertuples(index=False))
从 17.1 开始,以上操作将返回一个namedtuples 列表。
如果您想要一个普通元组列表,请将其name=None
作为参数传递:
list(data_set.itertuples(index=False, name=None))
解决方案 2:
怎么样:
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]
解决方案 3:
动机
许多数据集足够大,我们需要关注速度/效率。所以我本着这种精神提出了这个解决方案。它恰好也很简洁。
为了便于比较,我们删除该index
列
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)]
什么是 Quicker?
转弯records
最快,然后渐近收敛,zipmap
并且iter_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()
解决方案 4:
通用方法:
[tuple(x) for x in data_set.to_records(index=False)]
解决方案 5:
最有效、最简单的方法:
list(data_set.to_records())
您可以在此次调用之前过滤您需要的列。
解决方案 6:
这是一个矢量化方法(假设数据框data_set
被定义为df
),它返回list
如下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)]
将日期时间列设置为索引轴的想法是利用数据框中的参数来帮助将值转换Timestamp
为其相应的格式。datetime.datetime
`convert_datetime64DF.to_records
DateTimeIndex`
这将返回一个recarray
,然后可以list
使用.tolist
根据用例的更通用的解决方案是:
df.to_records().tolist() # Supply index=False to exclude index
解决方案 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)]
解决方案 8:
这个答案没有添加任何尚未讨论的答案,但这里有一些速度结果。我认为这应该可以解决评论中出现的问题。根据这三个值,所有这些看起来都是O(n) 。
TL;DR:tuples = list(df.itertuples(index=False, name=None))
并且tuples = list(zip(*[df[c].values.tolist() for c in df]))
并列速度最快。
我对结果进行了快速速度测试,得出了以下三条建议:
来自@pirsquared 的 zip 答案:
tuples = list(zip(*[df[c].values.tolist() for c in df]))
来自@wes-mckinney 的可接受答案:
tuples = [tuple(x) for x in df.values]
@ksindi 的 itertuples 回答符合
name=None
@Axel 的建议: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 版本彼此处于置信区间内。我怀疑它们在幕后做着同样的事情。
不过,这些速度测试可能无关紧要。突破我电脑内存的极限并不会花费大量时间,而且你真的不应该在大型数据集上这样做。这样做之后处理这些元组最终会变得非常低效。这不太可能成为你代码的主要瓶颈,所以只要坚持使用你认为最易读的版本就行了。
解决方案 9:
#try this one:
tuples = list(zip(data_set["data_date"], data_set["data_1"],data_set["data_2"]))
print (tuples)
解决方案 10:
更加 Python 化的方式:
df = data_set[['data_date', 'data_1', 'data_2']]
map(tuple,df.values)
解决方案 11:
将 Dataframe 列转换为没有索引的元组数组:
import pandas as pd
my_converted_array_tuples = pd.Dataframe(mydf['my_column_name']).to_records(index=False)
注意:如果需要索引,请删除索引行
扫码咨询,免费领取项目管理大礼包!