繁体   English   中英

更改过滤后的二维数组中的元素而无需列表理解,同时保留对原始内容的引用

[英]Changing elements in a filtered 2d array without list comprehension while keeping reference to original

我不确定该如何表达问题,但这是我想做的。

arr_first = np.array([[0,0,0,0],[0,0,0,0],[1,1,1,0],[1,1,1,0],[1,1,1,0],[1,1,2,0],[1,1,2,0],[2,2,2,0]])
arr_second = np.array([[0,0,0],[1,1,1],[1,1,2],[2,2,2]])

我正在尝试通过arr_first的前三个元素过滤arr_second ,导致...

[array([0, 0, 0, 0]), array([0, 0, 0, 0])]
[array([1, 1, 1, 0]), array([1, 1, 1, 0]), array([1, 1, 1, 0])]
[array([1, 1, 2, 0]), array([1, 1, 2, 0])]
[array([2, 2, 2, 0])]

然后,使用过滤后的2d数组,将32添加到每个2d数组中一个数组的第四个元素,如下所示:

[[ 0  0  0  0]
 [ 0  0  0 32]
 [ 1  1  1  0]
 [ 1  1  1  0]
 [ 1  1  1 32]
 [ 1  1  2  0]
 [ 1  1  2 32]
 [ 2  2  2 32]]

并将该数据保存到原始的arr_first

我当前使用的方法是使用python list comprehension语法:

for i in range(len(arr_second)):
    filtered = [row for row in arr_first if
                        arr_second[i][0] == row[0] and arr_second[i][1] == row[1] and arr_second[i][2] == row[2]]
    choosen_block = random.choice(filtered)
    choosen_block[3] += 32
print(arr_first)

这可行,但是在大型数据集中可能会非常慢。 因此,我尝试使用numpy的in1d进行过滤:

for i in range(len(arr_second)):
    filtered = arr_first[np.in1d(arr_first[:, 0], arr_second[i][0]) &
    np.in1d(arr_first[:, 1], arr_second[i][1]) &
    np.in1d(arr_first[:, 2], arr_second[i][2])]

    choosen_block = random.choice(filtered)
    choosen_block[3] += 32

但是,使用这种方法的问题是,改变不再保存在arr_first ,不像列表解析方法arr_first不再是一通参考filtered

我想知道,如果有人可以给我如何通过在变更来解决这个一些指导filtered也发生在arr_first而不必再拍列表,并用循环附加filtered它。

您可以使用Pandas进行groupbysample和更新arr_first

import pandas as pd

df = pd.DataFrame(arr_first)
inner_len = len(arr_first[0,:])
update_amt = 32
update_ix = 3

df.iloc[(df.groupby(list(range(inner_len)))
           .apply(lambda x: x.sample().index.values[0]).values), 
        update_ix] += update_amt

arr_first
[[ 0  0  0  0]
 [ 0  0  0 32]
 [ 1  1  1  0]
 [ 1  1  1 32]
 [ 1  1  1  0]
 [ 1  1  2 32]
 [ 1  1  2  0]
 [ 2  2  2 32]]

说明

  • 熊猫让我们通过唯一的行值集(例如[1,1,1,0]arr_first分组。 我用range()简化了groupby过程,但该命令实际上只是说:“按列0,列1,列2,列3分组”。 这有效地按arr_first每一行的完整值集合进行arr_first 这似乎有效地模仿了通过arr_first的值匹配arr_first行的arr_second

  • 一旦将行分组,就可以对每个组中的行进行sample ,并获取其索引。

  • 然后,将所选索引用于附加更新步骤。

  • 即使我们正在更新dfarr_first也将被更新,因为它是在创建df通过引用传递的( arr_first )。

我倾向于在Pandas中思考,但是可能有一个Numpy等效于这些步骤。

这是使您的方法可行的方法。

首先,为什么列表comp可以就地工作,而in1d却不能工作? list comp对arr_first的各个行进行操作,每个这样的行都是一个“视图”,即对arr_first的引用。 相比之下,in1d解决方案会创建一个遮罩,然后将其应用于数组。 使用掩码是“花式”或“高级”索引的一种形式。 由于原始索引所引用的orig数组的子集通常无法用偏移量来表示,因此跨步将强制执行复制,并且您以后所做的任何操作都不会影响orig数组。

一种简单的解决方法是不使用口罩。 而是将其转换为行索引向量,并在此向量上直接使用random.choice:

import numpy as np
import random

arr_first = np.array([[0,0,0,0],[0,0,0,0],[1,1,1,0],[1,1,1,0],[1,1,1,0],[1,1,2,0],[1,1,2,0],[2,2,2,0]])
arr_second = np.array([[0,0,0],[1,1,1],[1,1,2],[2,2,2]])

for i in range(len(arr_second)):
    filtered_idx = np.where(np.in1d(arr_first[:, 0], arr_second[i][0]) &
                            np.in1d(arr_first[:, 1], arr_second[i][1]) &
                            np.in1d(arr_first[:, 2], arr_second[i][2]))[0]

    choosen_block = random.choice(filtered_idx)
    arr_first[choosen_block, 3] += 32

print(arr_first)

样本输出:

[[ 0  0  0  0]
 [ 0  0  0 32]
 [ 1  1  1 32]
 [ 1  1  1  0]
 [ 1  1  1  0]
 [ 1  1  2  0]
 [ 1  1  2 32]
 [ 2  2  2 32]]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM