【问题标题】:Replacing NumPy array entries with their frequencies / values from dictionary用字典中的频率/值替换 NumPy 数组条目
【发布时间】:2015-03-10 03:37:26
【问题描述】:

问题:从两个输入数组中,我想输出一个数组,其中 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)。例如,如何将 3 转换为 0? 2)这似乎非常不雅/无效。有没有更好的方法来解决这个问题?

【问题讨论】:

    标签: python arrays numpy dictionary


    【解决方案1】:

    @memecs 解决方案是正确的,+1。但是,如果input_1 中的值非常大,即它们不是数组的索引,而是说它们是秒或其他可以取非常大值的整数数据,它将非常慢并且占用大量内存。

    在这种情况下,np.bincount(input_1[input_2]).size 等于 input_1 中的最大整数,True 值在 input_2 中。

    使用uniquebincount 会快得多。我们使用第一个提取input_1的唯一元素的索引,然后使用bincount计算这些索引在同一个数组中出现的频率,并根据10的值对它们进行加权数组input_2TrueFalse):

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

    此解决方案非常快,并且对内存的影响最小。归功于@Jaime,请参阅下面的评论。下面我报告我的原始答案,以不同的方式使用unique

    其他可能性

    使用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_2 中具有True 值的input_1 中的唯一元素的数量很多,则它将需要大量内存,因为创建并传递给where 的二维数组.为了减少内存占用,您可以使用 for 循环代替算法的第二步:

    #2nd step, but with a for loop.
    for j, val in enumerate(non_zero_hits):
        index = np.where(val == all_hits)[0]
        frequencies[index] = counts[j]
    print(frequencies[idx])
    

    第二种解决方案的内存占用非常小,但需要for 循环。这取决于您的典型数据输入大小和值,哪种解决方案最好。

    【讨论】:

    • 好点!内存占用可能很大。在使用 np.bincount s.t. 之前重新标记数据。 min=0 max
    • 你的顾虑很有道理,但正确的做法是不要构建二维数组,而是使用np.bincountweights参数:unq, idx = np.unique(array_1, return_inverse=True); freqs = np.bincount(idx, weights=array2)[idx]会给你一个快速,紧凑且节省内存的实现。
    • @Jaime,我实际上确信必须有更好的方法来做到这一点,并希望您发布更好的答案 :-) 如果您有时间,请发布它,或者将发布社区稍后自己回答
    • 请随意发表我的评论并将其添加到您认为合适的答案中:这只是同一主题的变体。
    【解决方案2】:

    np.bincount 就是你要找的东西。

    output_1 = np.bincount(input_1[input_2])[input_1]
    

    【讨论】:

      【解决方案3】:

      目前公认的 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])
      

      【讨论】:

        猜你喜欢
        • 2017-06-24
        • 1970-01-01
        • 2019-10-25
        • 1970-01-01
        • 2020-09-10
        • 1970-01-01
        • 2016-02-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多