Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用索引从数组中填充1D numpy数组_Python_Arrays_Pandas_Numpy_Vectorization - Fatal编程技术网

Python 使用索引从数组中填充1D numpy数组

Python 使用索引从数组中填充1D numpy数组,python,arrays,pandas,numpy,vectorization,Python,Arrays,Pandas,Numpy,Vectorization,背景 我有一个1D NumPy数组,用零初始化 import numpy as np section = np.zeros(1000) 然后我有一个熊猫数据框,其中索引分为两列: d= {'start': {0: 7200, 1: 7500, 2: 7560, 3: 8100, 4: 11400}, 'end': {0: 10800, 1: 8100, 2: 8100, 3: 8150, 4: 12000}} df = pd.DataFrame(data=d, columns=['s

背景

我有一个1D NumPy数组,用零初始化

import numpy as np
section = np.zeros(1000)
然后我有一个熊猫数据框,其中索引分为两列:

d= {'start': {0: 7200, 1: 7500, 2: 7560, 3: 8100, 4: 11400},
    'end': {0: 10800, 1: 8100, 2: 8100, 3: 8150, 4: 12000}}

df = pd.DataFrame(data=d, columns=['start', 'end'])
对于每一对索引,我想将numpy数组中相应索引的值设置为True

我当前的解决方案

我可以通过对数据帧应用函数来实现这一点:

def fill_array(row):
    section[row.start:row.end] = True

df.apply(fill_array, axis=1)
我想将此操作矢量化

这正如我所期望的,但是为了好玩,我想将操作矢量化。我对这方面不是很精通,而且我的在线搜索也没有让我走上正轨

如果可能的话,我将非常感谢您对如何将其转化为向量操作的任何建议。

向量化 您已经通过使用slice赋值完成了最重要的向量化,但是您无法使用slice对其进行完全向量化,因为python不支持“多个切片”

如果您真的非常想使用矢量化,您可以使用 “真实”索引,如下所示

indices = np.r_[tuple(slice(row.start, row.end) for row in df.itertuples())]
section[indices] = True
for start, end in slices_union:
    section[start:end] = True
但这很可能会更慢,因为它会创建一个带有索引的新临时数组

删除重复工作 也就是说,通过减少重复工作,您可以获得一些速度提升。具体来说,您可以使用,给您一组不相交的集合

在您的例子中,第一个间隔与除最后一个间隔之外的所有间隔重叠,因此您的数据帧相当于

d= {'start': {0: 7200, 1: 11400},
    'end': {0: 10800, 1: 12000}}
这将减少多达60%的工作量!但首先我们需要找到这些时间间隔。根据上述答案,我们可以通过以下方式实现:

slices = [(row.start, row.end) for row in df.itertuples()]
slices_union = []
for start, end in sorted(slices):
    if slices_union and slices_union[-1][1] >= start - 1:
        slices_union[-1][1] = max(slices_union[-1][1], end)
    else:
        slices_union.append([start, end])
然后你可以像这样使用这些(希望更小的切片)

indices = np.r_[tuple(slice(row.start, row.end) for row in df.itertuples())]
section[indices] = True
for start, end in slices_union:
    section[start:end] = True

接下来实现的技巧是,我们将在零初始化int数组的每个起点放置
1s
,在每个端点放置
-1s
。接下来是实际的技巧,因为我们将对其进行累加,为bin(开始-停止对)边界覆盖的位置提供非零的数字。因此,最后一步是寻找作为布尔数组的最终输出的非零。因此,我们将有两个矢量化解决方案,它们的实现如下所示-

def filled_array(start, end, length):
    out = np.zeros((length), dtype=int)
    np.add.at(out,start,1)
    np.add.at(out,end,-1)
    return out.cumsum()>0

def filled_array_v2(start, end, length): #Using @Daniel's suggestion
    out =np.bincount(start, minlength=length) - np.bincount(end, minlength=length)
    return out.cumsum().astype(bool)
样本运行-

In [2]: start
Out[2]: array([ 4,  7,  5, 15])

In [3]: end
Out[3]: array([12, 12,  7, 17])

In [4]: out = filled_array(start, end, length=20)

In [7]: pd.DataFrame(out) # print as dataframe for easy verification
Out[7]: 
        0
0   False
1   False
2   False
3   False
4    True
5    True
6    True
7    True
8    True
9    True
10   True
11   True
12  False
13  False
14  False
15   True
16   True
17  False
18  False
19  False

在您的实际用例中,会有多少个开始对、结束对?@Divakar最坏情况下10000对,以及一个1-300万个索引的NumPy数组。事实证明,我们可以矢量化,只需要改变我们的方式:)他可以,但我怀疑这是否值得。最后,我用
np.r\uu
给出了一个解决方案,我想这是最简单的解决方案。对于试图纠正术语,我深表歉意,但列表/数据框理解并不是一个矢量化的解决方案,特别是当放在大标题中时:)谢谢你的建议,@JonasAdler我必须对你的代码做一点小改动才能让它正常工作。原始对象抛出了一个
AttributeError:“str”对象没有属性“start”
错误。通过执行
df.itertuples()
而不是
df
可以轻松解决此问题。正如您所怀疑的,矢量化版本比迭代版本稍微慢一点,迭代版本为747µs,而迭代版本为649µs。作为比较,我的原始函数时钟为413µs。根据您的评论进行了更新。你试过另一个把戏吗?小诡辩:
maxlen
应该是
minlen
,因为如果你的
zero
数组太短
add.at
将失败。此外,为了提高性能,您可以执行
out=np.bincount(start,minlength=minlen)-np.bincount(end,minlength=minlen)
return out.cumsum().astype(bool)
自整数=0将在不进行比较的情况下解析为
TRUE
step@DanielF好的观点,非常感谢!编辑。那个名字不是正确的。如果输入参数覆盖了所有的索引,请将其留给OP来确定要提及的长度。谢谢@Divakar!这是一个很好的答案。我喜欢你建议的算法。聪明!我在245µs下测量,根据@DanielF的建议,每个循环的测量值仅为150µs。