计算对象数据类型重新排列中值的频率
Counting frequency of values in recarray of object datatype
这是我的输入:
data = np.array ([( 'a1' , np.NaN , 'a2' ),
( 'a1' , 'b2' , 'b1' ),
( 'c1' , 'c1' , np.NaN )],
dtype = [( 'A' , object ),
( 'B' , object ),
( 'C' , object )] ).view (np.recarray)
我想计算变量取的每个值的频率,我希望输出看起来像(比如输入 freq('A')
):
array [ ( 'a1' , 2 ) , ( 'c1' , 1 ) ]
我试过 np.bincounts()
但显然它不适用于对象数据类型。有没有办法使用 NumPy 来实现这一目标?
您可以使用 np.unique
为 data['A']
中的每个对象分配一个整数 "label"。然后你可以将 np.bincount
应用到 label
s:
In [18]: uniq, label = np.unique(data['A'], return_inverse=True)
In [19]: np.column_stack([uniq, np.bincount(label)])
Out[19]:
array([['a1', 2],
['c1', 1]], dtype=object)
请注意,对 dtype object
的 NumPy 数组的操作并不比对列表的等效操作快(而且通常更慢)。 (您需要将数组与原生 NumPy(即 non-object)dtypes 一起使用,以享受相对于纯 Python 的任何速度优势。)例如,如果您对 [= 使用列表字典,您的计算可能会更快21=],用collections.Counter
计算频率:
In [21]: data = {'A':['a1','a1','c1']}
In [22]: import collections
In [23]: collections.Counter(data['A'])
Out[23]: Counter({'a1': 2, 'c1': 1})
正如 hpaulj 指出的那样,当 data
也是 recarray 时,您可以使用 collection.Counter(data['A'])
。它比上面显示的 np.unique
/np.bincount
方法更快。因此,如果您必须使用对象的重新排列,那可能是您的最佳选择。
这是显示相对速度的基准:
data = np.random.choice(['a','b','c'], size=(300,)).astype(
[('A', object), ('B', object), ('C', object)]).view(np.recarray)
data2 = {key:data[key].tolist() for key in ['A','B','C']}
在列表的字典上使用 Counter
是最快的:
In [92]: %timeit collections.Counter(data2['A'])
100000 loops, best of 3: 13.7 µs per loop
在 dtype object
的数组上使用 Counter
是第二快的:
In [91]: %timeit collections.Counter(data['A'])
10000 loops, best of 3: 29.1 µs per loop
我最初的建议非常慢(虽然这是一个 apples-to-oranges 比较,因为这个 returns 是一个数组,而不是一个字典):
In [93]: %%timeit
....: uniq, label = np.unique(data['A'], return_inverse=True)
....: np.column_stack([uniq, np.bincount(label)])
....:
10000 loops, best of 3: 118 µs per loop
这是我的输入:
data = np.array ([( 'a1' , np.NaN , 'a2' ),
( 'a1' , 'b2' , 'b1' ),
( 'c1' , 'c1' , np.NaN )],
dtype = [( 'A' , object ),
( 'B' , object ),
( 'C' , object )] ).view (np.recarray)
我想计算变量取的每个值的频率,我希望输出看起来像(比如输入 freq('A')
):
array [ ( 'a1' , 2 ) , ( 'c1' , 1 ) ]
我试过 np.bincounts()
但显然它不适用于对象数据类型。有没有办法使用 NumPy 来实现这一目标?
您可以使用 np.unique
为 data['A']
中的每个对象分配一个整数 "label"。然后你可以将 np.bincount
应用到 label
s:
In [18]: uniq, label = np.unique(data['A'], return_inverse=True)
In [19]: np.column_stack([uniq, np.bincount(label)])
Out[19]:
array([['a1', 2],
['c1', 1]], dtype=object)
请注意,对 dtype object
的 NumPy 数组的操作并不比对列表的等效操作快(而且通常更慢)。 (您需要将数组与原生 NumPy(即 non-object)dtypes 一起使用,以享受相对于纯 Python 的任何速度优势。)例如,如果您对 [= 使用列表字典,您的计算可能会更快21=],用collections.Counter
计算频率:
In [21]: data = {'A':['a1','a1','c1']}
In [22]: import collections
In [23]: collections.Counter(data['A'])
Out[23]: Counter({'a1': 2, 'c1': 1})
正如 hpaulj 指出的那样,当 data
也是 recarray 时,您可以使用 collection.Counter(data['A'])
。它比上面显示的 np.unique
/np.bincount
方法更快。因此,如果您必须使用对象的重新排列,那可能是您的最佳选择。
这是显示相对速度的基准:
data = np.random.choice(['a','b','c'], size=(300,)).astype(
[('A', object), ('B', object), ('C', object)]).view(np.recarray)
data2 = {key:data[key].tolist() for key in ['A','B','C']}
在列表的字典上使用 Counter
是最快的:
In [92]: %timeit collections.Counter(data2['A'])
100000 loops, best of 3: 13.7 µs per loop
在 dtype object
的数组上使用 Counter
是第二快的:
In [91]: %timeit collections.Counter(data['A'])
10000 loops, best of 3: 29.1 µs per loop
我最初的建议非常慢(虽然这是一个 apples-to-oranges 比较,因为这个 returns 是一个数组,而不是一个字典):
In [93]: %%timeit
....: uniq, label = np.unique(data['A'], return_inverse=True)
....: np.column_stack([uniq, np.bincount(label)])
....:
10000 loops, best of 3: 118 µs per loop