问题:从两个输入数组中,我想输出一个数字,其频率为True值(来自input_2),对应于input_1的每个值。
import numpy as np # import everything from numpy
from scipy.stats import itemfreq
input_1 = np.array([3,6,6,3,6,4])
input_2 = np.array([False, True, True, False, False, True])
对于此示例,我想要的输出是:
output_1 = np.array([0,2,2,0,2,1])
我当前的方法涉及编辑input_1,因此只保留与True对应的值:
locs=np.where(input_2==True,input_1,0)
然后计算每个答案的频率,创建一个字典并将input_1的相应键替换为值(真实频率)。
loc_freq = itemfreq(locs)
dic = {}
for key,val in loc_freq:
dic[key]=val
print dic
for k, v in dic.iteritems():
input_1[input_1==k]=v
输出[3,2,2,3,2,1]。
这里的问题有两个: 1)这仍然没有对字典中没有的键做任何事情(因此应该更改为0)。例如,如何将3s转换为0? 2)这似乎非常不优雅/无效。有没有更好的方法来解决这个问题?
答案 0 :(得分:3)
@memecs解决方案是正确的,+ 1。然而,如果input_1
中的值非常大,即它们不是数组的索引,那么它将非常慢并占用大量内存,但是它们是秒或其他一些可能需要非常大的值的整数数据
在这种情况下,您np.bincount(input_1[input_2]).size
等于input_1
中True
的{{1}}值中的最大整数。
使用unique
和bincount
要快得多。我们使用第一个来提取input_2
的唯一元素的索引,然后使用input_1
来计算这些索引在同一个数组中出现的频率,并权衡它们bincount
或{{ 1}}基于数组1
(0
或input_2
)的值:
True
此解决方案非常快,并且对内存的影响最小。归功于@Jaime,请参阅下面的评论。下面我以不同的方式使用False
报告我的原始答案。
其他可能性
使用# extract unique elements and the indices to reconstruct the array
unq, idx = np.unique(input_1, return_inverse=True)
# calculate the weighted frequencies of these indices
freqs_idx = np.bincount(idx, weights=input_2)
# reconstruct the array of frequencies of the elements
frequencies = freqs_idx[idx]
print(frequencies)
:
unique
由于创建了2D数组,如果unique
中import numpy as np
input_1 = np.array([3, 6, 6, 3, 6, 4])
input_2 = np.array([False, True, True, False, False, True])
non_zero_hits, counts = np.unique(input_1[input_2], return_counts=True)
all_hits, idx = np.unique(input_1, return_inverse=True)
frequencies = np.zeros_like(all_hits)
#2nd step, with broadcasting
idx_non_zero_hits_in_all_hits = np.where(non_zero_hits[:, np.newaxis] - all_hits == 0)[1]
frequencies[idx_non_zero_hits_in_all_hits] = counts
print(frequencies[idx])
值input_1
中的唯一元素数量很多,则会产生大量内存的缺点并传递给True
。要减少内存占用,可以使用for循环代替算法的第二步:
input_2
第二种解决方案的内存占用非常小,但需要where
循环。这取决于您的典型数据输入大小和值,哪种解决方案最佳。
答案 1 :(得分:2)
np.bincount
正是您要找的。 p>
output_1 = np.bincount(input_1[input_2])[input_1]
答案 2 :(得分:0)
目前接受的bincount解决方案非常优雅,但numpy_indexed包为此类问题提供了更通用的解决方案:
import numpy_indexed as npi
idx = npi.as_index(input_1)
unique_labels, true_count_per_label = npi.group_by(idx).sum(input_2)
print(true_count_per_label[idx.inverse])