我不确定如何说出这个问题,但这就是我要做的事情。
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
更改来向我提供有关如何解决此问题的一些指导,而不是必须创建另一个列表并附加一个循环{{ 1}}到它。
答案 0 :(得分:1)
您可以将Pandas用于groupby
,sample
,并更新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]]
解释
Pandas允许我们通过唯一的行值集合对arr_first
进行分组,例如: [1,1,1,0]
。我将groupby
过程缩写为range()
,但命令实际上只是说:“按列0分组,然后是第1列,然后是第2列,然后是第3列”。这有效地按arr_first
中每行的全部值进行分组。这似乎有效地模仿了您使用arr_first
中的值匹配arr_second
行的方法。
一旦我们获得了组中的行,我们可以sample
每个组中的一行,并获取其索引。
然后,使用所选索引进行添加更新步骤。
即使我们正在更新df
,arr_first
也会更新,因为在df
的创建过程中通过引用传递(有点)。
我倾向于在熊猫中思考,但可能有一个Numpy等同于这些步骤。
答案 1 :(得分:1)
以下是如何使您的方法有效。
首先,为什么列表comp就地工作,而in1d却没有?列表comp对arr_first的各行进行操作,每个这样的行都是“视图”,即对arr_first的引用。相比之下,in1d soln会创建一个掩码,然后将其应用于阵列。使用掩码是“花式”或“高级”索引的一种形式。由于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]]