tru*_*512 4 python arrays performance pandas
我正在尝试有效地创建一个数组,如x:
input = [0, 1, 2, 3, 4, 5, 6]
x = [ [0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6] ]
Run Code Online (Sandbox Code Playgroud)
我尝试过简单的for循环,真正的用例需要很长时间.
(延伸版本)
我有一个400k行的长数据帧,我需要n从当前迭代的元素分割成下一个元素的数组.目前我将它分组,就像下面的process_data功能一样.
一个for基于简单的迭代需要永远在这里(我的硬件上2.5分钟是特定的).我搜索itertools和pandas文档,尝试在这里搜索,找不到任何合适的解决方案.
我目前超级耗时的实现:
class ModelInputParsing(object):
def __init__(self, data):
self.parsed_dataframe = data.fillna(0)
def process_data(self, lb=50):
self.X, self.Y = [],[]
for i in range(len(self.parsed_dataframe)-lb):
self.X.append(self.parsed_dataframe.iloc[i:(i+lb),-2])
self.Y.append(self.parsed_dataframe.iloc[(i+lb),-1])
return (np.array(self.X), np.array(self.Y))
Run Code Online (Sandbox Code Playgroud)
输入数据如下所示(Bid提到的位置input):
Bid Changes Expected
0 1.20102 NaN 0.000000
1 1.20102 0.000000 0.000000
2 1.20102 0.000000 0.000042
3 1.20102 0.000000 0.000017
4 1.20102 0.000000 0.000025
5 1.20102 0.000000 0.000025
6 1.20102 0.000000 0.000100
...
Run Code Online (Sandbox Code Playgroud)
输出应该如下所示:
array([[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, ...,
8.34465027e-06, -8.34465027e-06, 0.00000000e+00],
[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, ...,
-8.34465027e-06, 0.00000000e+00, 3.33786011e-05],
[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, ...,
0.00000000e+00, 3.33786011e-05, 0.00000000e+00],
...,
[ 0.00000000e+00, 8.34465027e-06, 1.66893005e-05, ...,
-8.34465027e-06, 0.00000000e+00, 0.00000000e+00],
[ 8.34465027e-06, 1.66893005e-05, -8.34465027e-06, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 1.66893005e-05, -8.34465027e-06, 0.00000000e+00, ...,
0.00000000e+00, 0.00000000e+00, 1.66893005e-05]], dtype=float32)
len(x)
399950
Run Code Online (Sandbox Code Playgroud)
下面我介绍x[0]和x[1].这里的关键是值如何在下一个数组中移回一个位置.例如,第一个非零值从位置移动7到6(0基位置).
第一个要素:
x[0]
array([ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, -4.16040421e-05, 2.49147415e-05,
-8.34465027e-06, 0.00000000e+00, -7.49230385e-05,
...,
2.50339508e-05, -8.34465027e-06, 3.33786011e-05,
-2.50339508e-05, -8.34465027e-06, 8.34465027e-06,
-8.34465027e-06, 0.00000000e+00], dtype=float32)
len(x[0])
50
Run Code Online (Sandbox Code Playgroud)
第二个要素:
x[1]
array([ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
-4.16040421e-05, 2.49147415e-05, -8.34465027e-06,
0.00000000e+00, -7.49230385e-05, -1.58131123e-04,
....,
-8.34465027e-06, 3.33786011e-05, -2.50339508e-05,
-8.34465027e-06, 8.34465027e-06, -8.34465027e-06,
0.00000000e+00, 3.33786011e-05], dtype=float32)
len(x[1])
50
Run Code Online (Sandbox Code Playgroud)
我很好奇是否有办法更有效地完成这项工作,因为我很快计划解析+20m行的数据集.
zip() 加上一些切片可以做到这一点:
>>> list(zip(input[0:], input[1:], input[2:]))
[(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]
Run Code Online (Sandbox Code Playgroud)
如果您需要将列表元素作为列表,请使用:
>>> list(map(list, zip(input[0:], input[1:], input[2:])))
[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
Run Code Online (Sandbox Code Playgroud)
一般来说,如果你需要n元组而不是三元组,你可以这样做:
>>> list(zip(*(input[i:] for i in range(3))))
[(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]
Run Code Online (Sandbox Code Playgroud)
要么
>>> list(map(list, zip(*(input[i:] for i in range(3)))))
[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
Run Code Online (Sandbox Code Playgroud)
另一种方法:
>>> [input[i:i+3] for i in range(len(input)-3+1)]
[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
Run Code Online (Sandbox Code Playgroud)
建立:
import timeit
def ff1(input):
return list(map(list, zip(input[0:], input[1:], input[2:])))
def ff2(input):
return list(map(list, zip(*(input[i:] for i in range(3)))))
def ff3(input):
return [input[i:i+3] for i in range(len(input)-3+1)]
def jg(input):
for i in range(0, len(input) - 2):
yield input[i:i+3]
def jg1(input):
return list(jg(input))
import itertools
def n(input, n=3):
i = list(itertoopls.tee(input, n))
for p, it in enumerate(i):
next(itertools.slice(it, p, p), None)
return zip(*i)
def n1(input, _n=3):
return list(map(list, n(input, _n)))
from numpy.lib.stride_tricks import as_strided
def strided_groupby(n, l=3):
s = n.strides[0]
return as_strided(n, shape=(n.size-l+1,l), strides=(s,s))
Run Code Online (Sandbox Code Playgroud)
结果:
>>> input = list(range(10000))
>>> timeit.timeit(stmt='ff1(input)', globals=globals(), number=1000)
1.4750333260162733
>>> timeit.timeit(stmt='ff2(input)', globals=globals(), number=1000)
1.486136345018167
>>> timeit.timeit(stmt='ff3(input)', globals=globals(), number=1000)
1.6864491199958138
>>> timeit.timeit(stmt='jg1(input)', globals=globals(), number=1000)
2.300399674975779
>>> timeit.timeit(stmt='n1(input)', globals=globals(), number=1000)
2.2269885840360075
>>> input_arr = np.array(input)
>>> timeit.timeit(stmt='strided_groupby(input_arr)', globals=globals(), number=1000)
0.01855822204379365
Run Code Online (Sandbox Code Playgroud)
请注意,内部列表转换会浪费大量的CPU周期.如果你能负担得起元组而不是列表,那么最里面的序列(即(0,1,2),(1,2,3),...)将会表现得更好.
为了公平比较,我将相同的列表转换应用于所有算法.