计算数组中所选差异的有效方法

时间:2016-10-05 11:39:49

标签: python arrays numpy

我有两个数组作为模拟脚本的输出,其中一个包含ID和一次,例如:

ids = np.array([2, 0, 1, 0, 1, 1, 2])
times = np.array([.1, .3, .3, .5, .6, 1.2, 1.3])

这些数组总是大小相同。现在我需要计算times的差异,但仅适用于具有相同ids的时间。当然,我可以简单地遍历不同的ids

for id in np.unique(ids):
    diffs = np.diff(times[ids==id])
    print diffs
    # do stuff with diffs

然而,这是非常低效的,并且两个阵列可能非常大。有谁知道如何更有效地做到这一点?

4 个答案:

答案 0 :(得分:3)

您可以使用array.argsort()并忽略与ID中的更改相对应的值:

>>> id_ind = ids.argsort(kind='mergesort')
>>> times_diffs = np.diff(times[id_ind])
array([ 0.2, -0.2,  0.3,  0.6, -1.1,  1.2])

要查看需要丢弃的值,可以使用计数器计算每个ID的次数(from collections import Counter

或者只是排序ID,并查看其diff非零的位置:这些是id更改的索引,以及时间差异无关紧要的位置:

times_diffs[np.diff(ids[id_ind]) == 0] # ids[id_ind] being the sorted indices sequence

最后你可以用np.split和np.where:

分割这个数组
np.split(times_diffs, np.where(np.diff(ids[id_ind]) != 0)[0])

正如您在评论中提到的,argsort()默认算法(quicksort)可能无法在等于时间之间保留顺序,因此必须使用argsort(kind='mergesort')选项。

答案 1 :(得分:2)

np.argsort

告诉你ids
inds = np.argsort(ids, kind='mergesort')
>>> array([1, 3, 2, 4, 5, 0, 6])

现在按{H} times排序np.diff,然后添加nan

diffs = np.concatenate(([np.nan], np.diff(times[inds])))
>>> diffs 
array([ nan,  0.2, -0.2,  0.3,  0.6, -1.1,  1.2])

除边界外,这些差异是正确的。让我们计算那些

boundaries = np.concatenate(([False], ids[inds][1: ] == ids[inds][: -1]))
>>> boundaries
array([False,  True, False,  True,  True, False,  True], dtype=bool)

现在我们可以做到

diffs[~boundaries] = np.nan

让我们看看我们得到了什么:

>>> ids[inds]
array([0, 0, 1, 1, 1, 2, 2])

>>> times[inds]
array([ 0.3,  0.5,  0.3,  0.6,  1.2,  0.1,  1.3])

>>> diffs
array([ nan,  0.2,  nan,  0.3,  0.6,  nan,  1.2])

答案 2 :(得分:1)

我添加了另一个答案,因为即使numpy中有可能出现这些问题,我认为更高级pandas对他们来说更为自然。

pandas中,您可以在创建数据框后一步完成此操作:

df = pd.DataFrame({'ids': ids, 'times': times})

df['diffs'] = df.groupby(df.ids).transform(pd.Series.diff)

这给出了:

>>> df
   ids  times  diffs
0    2    0.1    NaN
1    0    0.3    NaN
2    1    0.3    NaN
3    0    0.5    0.2
4    1    0.6    0.3
5    1    1.2    0.6
6    2    1.3    1.2

答案 3 :(得分:1)

numpy_indexed包(免责声明:我是其作者)包含用于这类分组操作的高效且灵活的功能:

import numpy_indexed as npi
unique_ids, diffed_time_groups = npi.group_by(keys=ids, values=times, reduction=np.diff)

与pandas不同,它不需要专门的数据结构来执行这种相当基本的操作。