【问题标题】:How can I use a dictionary to map array indices to the corresponding argsorted indices if all indices are in sub-arrays?如果所有索引都在子数组中,如何使用字典将数组索引映射到相应的 argsorted 索引?
【发布时间】:2018-06-16 12:49:27
【问题描述】:

我有多个数组对应于时间序列的数据参数。数据参数包括速度、发生时间、发生日期、发生月份、发生时间等。

我正在尝试从最高到最低的出现频率查找与指定数据参数的分组相对应的索引。

举个简单的例子,考虑以下几点:

import numpy as np

speed = np.array([4, 6, 8, 3, 6, 9, 7, 6, 4, 3])*100
elap_hr = sorted(np.random.randint(low=1, high=40, size=10))
## ... other time parameter arrays

print(speed)
# [400 600 800 300 600 900 700 600 400 300]

print(elap_hr)
# [ 1  2  6  7 13 19 21 28 33 38]

所以观察到speed = 400(2次出现)对应于elapsed hours = 1, 33speed = 600(出现 3 次)对应于 elapsed hours = 2, 13, 28

对于这个例子,假设我有兴趣按出现频率对speed 进行分组。一旦有了将speed 从最高频率到最低频率分组的索引,我就可以在其他数据参数数组(如elap_hr)上应用相同的索引。

我先排序和argsortspeed;然后我找到 sorted speed 的独特元素。我将这些组合起来以找到与排序唯一 speed 相对应的排序 speed 的索引,这些索引在排序唯一 speed 中按值分组为子数组。

def get_sorted_data(data, sort_type='default'):
    if sort_type == 'default':
        res = sorted(data)
    elif sort_type == 'argsort':
        res = np.argsort(data)
    elif sort_type == 'by size':
        res = sorted(data, key=len)
    return res

def sort_data_by_frequency(data):
    uniq_data = np.unique(data)
    sorted_data = get_sorted_data(data)
    res = [np.where(sorted_data == uniq_data[i])[0] for i in range(len(uniq_data))]
    res = get_sorted_data(res, 'by size')[::-1]
    return res 

sorted_speed = get_sorted_data(speed)
argsorted_speed = get_sorted_data(speed, 'argsort')
freqsorted_speed = sort_data_by_frequency(speed)

print(sorted_speed)
# [300, 300, 400, 400, 600, 600, 600, 700, 800, 900]
print(argsorted_speed)
# [3 9 0 8 1 4 7 6 2 5]
print(freqsorted_speed)
# [array([4, 5, 6]), array([2, 3]), array([0, 1]), array([9]), array([8]), array([7])]

freqsorted_speed中,第一个子数组[4, 5, 6]对应于排序数组中元素[600, 600, 600]的索引。

到目前为止还可以。但是,我希望索引适用于所有数据参数数组。所以,我需要将 argsorted 索引映射到原始数组索引。

def get_dictionary_mapping(keys, values):
    ## since all indices are unique, there is no worry about identical keys
    return dict(zip(keys, values))

idx_orig = np.array([i for i in range(len(argsorted_speed))], dtype=int)
index_to_index_map = get_dictionary_mapping(idx_orig, argsorted_speed)

print(index_to_index_map)
# {0: 3, 1: 9, 2: 0, 3: 8, 4: 1, 5: 4, 6: 7, 7: 6, 8: 2, 9: 5}

print(speed[idx_orig])
# [400 600 800 300 600 900 700 600 400 300]

print(speed[argsorted_speed])
# [300 300 400 400 600 600 600 700 800 900]

print([index_to_index_map[idx_orig[i]] for i in range(len(idx_orig))])
# [3, 9, 0, 8, 1, 4, 7, 6, 2, 5]

我拥有完成我想要的所有必要的部分。但我不太确定如何把它放在一起。任何建议将不胜感激。

编辑:

作为最终结果,我希望将 speed 的原始索引按频率分组,如下所示:

res = [[1, 4, 7], [3, 9], [0, 8], ...]
## corresponds to 3 600's, 2 300's, 2 400's, etc.
## for values of equal frequency, the secondary grouping is from min-to-max

这样,我可以按第 n 个最频繁的值或频率本身来选择值。

【问题讨论】:

  • 您能否更具体地说明您想要的最终结果是什么?
  • 我刚刚添加了一个编辑部分来澄清。

标签: python-3.x sorting numpy indexing frequency


【解决方案1】:

你想要的结果如下:

>>> idx = np.argsort(speed)
>>> res = sorted(np.split(idx, np.flatnonzero(np.diff(speed[idx])) + 1), key=len, reverse=True)
>>> res
[array([1, 4, 7]), array([3, 9]), array([0, 8]), array([6]), array([2]), array([5])]

【讨论】:

  • @mikey speed[idx] 是排序后的速度数组,特别是相等的元素将彼此相邻。如果我们采用连续的差异,这些将在相同元素的块内为零,非零差异表示块的边界。 flatnonzero 返回这些边界的索引,但我们必须加 1,因为 diff 将元素 ii+1 之间的差异放在 isplit 给定 ii-1i.
  • 我刚刚意识到 idx 部分并在您回复之前几秒钟删除了我的评论(因为编辑太晚了)。但是感谢您澄清在 flatnonzero 例程中添加 1。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多