用字典中的频率/值替换 NumPy 数组条目
Replacing NumPy array entries with their frequencies / values from dictionary
问题:我想从两个输入数组中输出一个数组,其真值频率(来自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)这看起来很不优雅/无效。有没有更好的方法来解决这个问题?
np.bincount
就是您要找的。
output_1 = np.bincount(input_1[input_2])[input_1]
@memecs 解决方案正确,+1。但是,如果 input_1
中的值非常大,即它们不是数组的索引,而是说它们是秒或其他一些可以取非常大值的整数数据,它将非常慢并且占用大量内存.
在这种情况下,np.bincount(input_1[input_2]).size
等于 input_1
中的最大整数,input_2
中的值为 True
。
使用unique
and bincount
要快得多。我们使用第一个来提取 input_1
的唯一元素的索引,然后使用 bincount
来计算这些索引在同一数组中出现的频率,并对它们进行权衡 1
或 0
基于数组的值input_2
(True
或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)
这个解决方案非常快并且对内存的影响最小。感谢@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
中的唯一元素数量很多,这将需要大量内存,因为2D数组已创建并传递给 where
。为了减少内存占用,您可以在算法的第 2 步中使用 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
循环。这取决于您的典型数据输入大小和最佳解决方案的值。
目前接受的 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])
问题:我想从两个输入数组中输出一个数组,其真值频率(来自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)这看起来很不优雅/无效。有没有更好的方法来解决这个问题?
np.bincount
就是您要找的。
output_1 = np.bincount(input_1[input_2])[input_1]
@memecs 解决方案正确,+1。但是,如果 input_1
中的值非常大,即它们不是数组的索引,而是说它们是秒或其他一些可以取非常大值的整数数据,它将非常慢并且占用大量内存.
在这种情况下,np.bincount(input_1[input_2]).size
等于 input_1
中的最大整数,input_2
中的值为 True
。
使用unique
and bincount
要快得多。我们使用第一个来提取 input_1
的唯一元素的索引,然后使用 bincount
来计算这些索引在同一数组中出现的频率,并对它们进行权衡 1
或 0
基于数组的值input_2
(True
或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)
这个解决方案非常快并且对内存的影响最小。感谢@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
中的唯一元素数量很多,这将需要大量内存,因为2D数组已创建并传递给 where
。为了减少内存占用,您可以在算法的第 2 步中使用 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
循环。这取决于您的典型数据输入大小和最佳解决方案的值。
目前接受的 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])