重复,但以可变大小的块以numpy格式

如何解决重复,但以可变大小的块以numpy格式

我有一个数组,该数组是不同块的串联:

a = np.array([0,1,2,10,11,20,21,22,23])
#             >     <  >    <  >            <
chunks = np.array([3,4])
repeats = np.array([1,3,2])

在上面的示例中,以新的十年开始的每个细分都是一个单独的“块”,我想重复一遍。每个块的大小和重复次数是已知的。我无法进行重塑,后跟kronrepeat,因为块的大小不同。

我想要的结果是

np.array([0,23,23])
# repeats:>  1  <  >         3          <  >              2             <

这很容易循环执行:

in_offset = np.r_[0,np.cumsum(chunks[:-1])]
out_offset = np.r_[0,np.cumsum(chunks[:-1] * repeats[:-1])]
output = np.zeros((chunks * repeats).sum(),dtype=a.dtype)
for c in range(len(chunks)):
    for r in range(repeats[c]):
        for i in range(chunks[c]):
            output[out_offset[c] + r * chunks[c] + i] = a[in_offset[c] + i]

这导致以下矢量化:

regions = chunks * repeats
index = np.arange(regions.sum())

segments = np.repeat(chunks,repeats)
resets = np.cumsum(segments[:-1])
offsets = np.zeros_like(index)
offsets[resets] = segments[:-1]
offsets[np.cumsum(regions[:-1])] -= chunks[:-1]

index -= np.cumsum(offsets)

output = a[index]

有没有更有效的方法来矢量化此问题?只是我们很清楚,我不是在要求代码审查。我对这些函数调用如何协同工作感到满意。我想知道是否可以使用完全不同的(更有效的)函数调用组合来达到相同的结果。

这个问题的灵感来自my answerthis question

解决方法

(与其他答案相比)执行任务的另一种 numpythonic 方法是:

result = np.concatenate([ np.tile(tbl,rpt) for tbl,rpt in
    zip(np.split(a,np.cumsum(chunks[:-1])),repeats) ])

结果是:

array([ 0,1,2,10,11,20,21,22,23,23])
,

对于那些属于范围数组的块,我们可以直接在输入数组上工作,从而避免了最后的索引步骤,这应该可以改善-

# https://stackoverflow.com/a/47126435/ @Divakar
def create_ranges(starts,ends,l):
    clens = l.cumsum()
    ids = np.ones(clens[-1],dtype=int)
    ids[0] = starts[0]
    ids[clens[:-1]] = starts[1:] - ends[:-1]+1
    out = ids.cumsum()
    return out

s = np.r_[0,chunks.cumsum()]
starts = a[np.repeat(s[:-1],repeats)]
l = np.repeat(chunks,repeats)
ends = starts+l
out = create_ranges(starts,l)
,

比其他答案更能解决此问题的“ numpythonic ”方法是-

np.concatenate(np.repeat(np.split(a,np.cumsum(chunks))[:-1],repeats))
array([ 0,23])

注意,没有明确的for循环。

np.split有一个隐式循环,如@Divakar指出的那样。)


编辑:基准(MacBook Pro 13)-

正如@Mad Physicist在他的帖子中指出的那样,Divakar的解决方案可以更好地扩展到更大的阵列,大块和重复。

enter image description here

,

出于参考目的,我在这里对工作解决方案进行了基准测试。

def MadPhysicist1(a,chunks,repeats):
    in_offset = np.r_[0,np.cumsum(chunks[:-1])]
    out_offset = np.r_[0,np.cumsum(chunks[:-1] * repeats[:-1])]
    output = np.zeros((chunks * repeats).sum(),dtype=a.dtype)
    for c in range(len(chunks)):
        for r in range(repeats[c]):
            for i in range(chunks[c]):
                output[out_offset[c] + r * chunks[c] + i] = a[in_offset[c] + i]
    return output

def MadPhysicist2(a,repeats):
    regions = chunks * repeats
    index = np.arange(regions.sum())

    segments = np.repeat(chunks,repeats)
    resets = np.cumsum(segments[:-1])
    offsets = np.zeros_like(index)
    offsets[resets] = segments[:-1]
    offsets[np.cumsum(regions[:-1])] -= chunks[:-1]

    index -= np.cumsum(offsets)

    output = a[index]
    return output

def create_ranges(starts,dtype=int)
    ids[0] = starts[0]
    ids[clens[:-1]] = starts[1:] - ends[:-1]+1
    out = ids.cumsum()
    return out

def Divakar(a,repeats):
    s = np.r_[0,chunks.cumsum()]
    starts = a[np.repeat(s[:-1],repeats)]
    l = np.repeat(chunks,repeats)
    ends = starts+l
    return create_ranges(starts,l)

def Valdi_Bo(a,repeats):
    return np.concatenate([np.tile(tbl,rpt in
                           zip(np.split(a,repeats)])

def AkshaySehgal(a,repeats):
    return np.concatenate(np.repeat(np.split(a,repeats))

我研究了三种输入大小的时序:〜100,〜1000和〜10k元素:

np.random.seed(0xA)
chunksA = np.random.randint(1,size=20)   # ~100 elements
repeatsA = np.random.randint(1,size=20)
arrA = np.random.randint(100,size=chunksA.sum())

np.random.seed(0xB)
chunksB = np.random.randint(1,100,size=20)  # ~1000 elements
repeatsB = np.random.randint(1,size=20)
arrB = np.random.randint(100,size=chunksB.sum())

np.random.seed(0xC)
chunksC = np.random.randint(1,size=200)  # ~10000 elements
repeatsC = np.random.randint(1,size=200)
arrC = np.random.randint(100,size=chunksC.sum())

以下是一些结果:

|               |    A    |    B    |    C    |
+---------------+---------+---------+---------+
| MadPhysicist1 | 1.92 ms |   16 ms |  159 ms |
| MadPhysicist2 | 85.5 µs |  153 µs |  744 µs |
| Divakar       | 75.9 µs | 95.9 µs |  312 µs |
| Valdi_Bo      |  370 µs |  369 µs |  3.4 ms |
| AkshaySehgal  |  163 µs |  165 µs | 1.24 ms |
,
    for rep,num in zip(repeats,chunks):
        res.extend(list(range(num))*rep)

[0,3,3]

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-