用字典中的频率/值替换NumPy数组条目

时间:2015-01-12 11:22:03

标签: python arrays numpy dictionary

问题:从两个输入数组中,我想输出一个数字,其频率为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)这似乎非常不优雅/无效。有没有更好的方法来解决这个问题?

3 个答案:

答案 0 :(得分:3)

@memecs解决方案是正确的,+ 1。然而,如果input_1中的值非常大,即它们不是数组的索引,那么它将非常慢并占用大量内存,但是它们是秒或其他一些可能需要非常大的值的整数数据

在这种情况下,您np.bincount(input_1[input_2]).size等于input_1True的{​​{1}}值中的最大整数。

使用uniquebincount要快得多。我们使用第一个来提取input_2的唯一元素的索引,然后使用input_1来计算这些索引在同一个数组中出现的频率,并权衡它们bincount或{{ 1}}基于数组10input_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数组,如果uniqueimport 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正是您要找的。

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])