सुन्न: एक सरणी में अद्वितीय मूल्यों के लिए सबसे कुशल आवृत्ति मायने रखती है


244

में numpy/ scipy, वहाँ एक है कुशल तरीका एक सरणी में अद्वितीय मानों के लिए आवृत्ति मायने रखता है पाने के लिए?

इन पंक्तियों के साथ कुछ:

x = array( [1,1,1,2,2,2,5,25,1,1] )
y = freq_count( x )
print y

>> [[1, 5], [2,3], [5,1], [25,1]]

(आप के लिए, आर उपयोगकर्ताओं को वहाँ, मैं मूल रूप से table()समारोह के लिए देख रहा हूँ )


5
है collections.Counter(x)पर्याप्त?
पाइलैंग

1
यह बेहतर होगा कि मुझे लगता है कि यदि आप अब इस उत्तर को अपने प्रश्न के लिए सही मानते हैं: stackoverflow.com/a/25943480/90569698
आउटकास्ट

संग्रह। मुठभेड़ काफी धीमी है। मेरी पोस्ट देखें: stackoverflow.com/questions/41594940/…
सेमीबी नोरिमकी

जवाबों:


161

पर एक नज़र रखना np.bincount:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.bincount.html

import numpy as np
x = np.array([1,1,1,2,2,2,5,25,1,1])
y = np.bincount(x)
ii = np.nonzero(y)[0]

और तब:

zip(ii,y[ii]) 
# [(1, 5), (2, 3), (5, 1), (25, 1)]

या:

np.vstack((ii,y[ii])).T
# array([[ 1,  5],
         [ 2,  3],
         [ 5,  1],
         [25,  1]])

या फिर आप गिनती और अद्वितीय मूल्यों को जोड़ना चाहते हैं।


42
नमस्ते, यह काम नहीं करेगा अगर x के तत्वों में इंट के अलावा अन्य dtype है।
मनोज

7
यह काम नहीं करेगा अगर वे गैर नकारात्मक चींटियों के अलावा कुछ भी हो, और यह बहुत ही अयोग्य होगा अगर चींटियों को बाहर निकाल दिया जाता है।
एरिक

संख्यात्मक संस्करण 1.10 के साथ मैंने पाया कि पूर्णांक की गणना के लिए, यह np.unique से लगभग 6 गुना तेज है। इसके अलावा, ध्यान दें कि यह नकारात्मक आवृत्तियों को भी गिनता है, यदि सही पैरामीटर दिए गए हैं।
जिहुँ

@ मेराज: मेरे तत्व x सरणियाँ हैं। मैं jme के समाधान का परीक्षण कर रहा हूं।
कैटालिना चिरकु

508

Numpy 1.9 के रूप में, सबसे आसान और सबसे तेज़ तरीका केवल उपयोग करना है numpy.unique, जिसमें अब एक return_countsकीवर्ड तर्क है:

import numpy as np

x = np.array([1,1,1,2,2,2,5,25,1,1])
unique, counts = np.unique(x, return_counts=True)

print np.asarray((unique, counts)).T

जो देता है:

 [[ 1  5]
  [ 2  3]
  [ 5  1]
  [25  1]]

के साथ एक त्वरित तुलना scipy.stats.itemfreq:

In [4]: x = np.random.random_integers(0,100,1e6)

In [5]: %timeit unique, counts = np.unique(x, return_counts=True)
10 loops, best of 3: 31.5 ms per loop

In [6]: %timeit scipy.stats.itemfreq(x)
10 loops, best of 3: 170 ms per loop

22
अपडेट करने के लिए धन्यवाद! यह अब, सही जवाब है, IMO।
Erve1879

1
BAM! यही कारण है कि हम अपडेट करते हैं ... जब हमें इन जैसे उत्तर मिलते हैं। इतना लंबा सुपाड़ा 1.8। हम इसे सूची के शीर्ष पर कैसे ला सकते हैं?
यूजर 1269942

यदि आपको त्रुटि मिलती है: TypeError: unique () को एक अनपेक्षित कीवर्ड तर्क 'return_counts' मिला, बस करें: अद्वितीय, मायने रखता है = np.unique (x, True)
NumesSanguis

3
@NumesSanguis आप किस संस्करण का उपयोग कर रहे हैं? V1.9 से पहले, return_countsकीवर्ड तर्क मौजूद नहीं था, जो अपवाद की व्याख्या कर सकता है। उस स्थिति में, डॉक्स सुझाव देता np.unique(x, True)है कि इसके बराबर है np.unique(x, return_index=True), जो मायने नहीं रखता है।
jme

1
पुराने सुन्न संस्करणों में एक ही चीज़ प्राप्त करने के लिए विशिष्ट मुहावरा था unique, idx = np.unique(x, return_inverse=True); counts = np.bincount(idx)। जब इस सुविधा को जोड़ा गया था ( यहाँ देखें ) कुछ अनौपचारिक परीक्षण में return_counts5x से अधिक तेजी से क्लॉकिंग का उपयोग किया गया था ।
जैमे

133

अद्यतन: मूल उत्तर में उल्लिखित विधि को हटा दिया गया है, हमें इसके बजाय नए तरीके का उपयोग करना चाहिए:

>>> import numpy as np
>>> x = [1,1,1,2,2,2,5,25,1,1]
>>> np.array(np.unique(x, return_counts=True)).T
    array([[ 1,  5],
           [ 2,  3],
           [ 5,  1],
           [25,  1]])

मूल उत्तर:

आप scipy.stats.itemfreq का उपयोग कर सकते हैं

>>> from scipy.stats import itemfreq
>>> x = [1,1,1,2,2,2,5,25,1,1]
>>> itemfreq(x)
/usr/local/bin/python:1: DeprecationWarning: `itemfreq` is deprecated! `itemfreq` is deprecated and will be removed in a future version. Use instead `np.unique(..., return_counts=True)`
array([[  1.,   5.],
       [  2.,   3.],
       [  5.,   1.],
       [ 25.,   1.]])

1
अब तक के सबसे पायथोनिक दृष्टिकोण की तरह लगता है। इसके अलावा, मुझे 100k x 100k matrices पर np.bincount के साथ "वांछित सरणी के लिए बहुत गहरी वस्तु" मुद्दों का सामना करना पड़ा।
मेटासेक्विया

1
मैं इसके बजाय मूल प्रश्न प्रस्तुत करने वाले को सुझाव देता हूं कि पहले वाले से इस एक के उत्तर को बदलने के लिए, इसकी
विज़िबिलिटी

यह 0.14 से पहले के संस्करणों के लिए धीमा है, हालांकि।
जेसन एस

ध्यान दें कि यदि सरणी स्ट्रिंग्स से भरा है, तो लौटाए गए प्रत्येक आइटम में दोनों तत्व भी स्ट्रिंग हैं।
user1269942

आइटमफ्रेक की तरह लगता है हटा दिया गया है
टेरेंस Parr

48

मुझे इसमें भी दिलचस्पी थी, इसलिए मैंने थोड़ा प्रदर्शन तुलना ( परफ्लोट , मेरा एक पालतू प्रोजेक्ट) का उपयोग किया। परिणाम:

y = np.bincount(a)
ii = np.nonzero(y)[0]
out = np.vstack((ii, y[ii])).T

अब तक सबसे तेज है। (लॉग-स्केलिंग पर ध्यान दें।)

यहां छवि विवरण दर्ज करें


प्लॉट जनरेट करने के लिए कोड:

import numpy as np
import pandas as pd
import perfplot
from scipy.stats import itemfreq


def bincount(a):
    y = np.bincount(a)
    ii = np.nonzero(y)[0]
    return np.vstack((ii, y[ii])).T


def unique(a):
    unique, counts = np.unique(a, return_counts=True)
    return np.asarray((unique, counts)).T


def unique_count(a):
    unique, inverse = np.unique(a, return_inverse=True)
    count = np.zeros(len(unique), np.int)
    np.add.at(count, inverse, 1)
    return np.vstack((unique, count)).T


def pandas_value_counts(a):
    out = pd.value_counts(pd.Series(a))
    out.sort_index(inplace=True)
    out = np.stack([out.keys().values, out.values]).T
    return out


perfplot.show(
    setup=lambda n: np.random.randint(0, 1000, n),
    kernels=[bincount, unique, itemfreq, unique_count, pandas_value_counts],
    n_range=[2 ** k for k in range(26)],
    logx=True,
    logy=True,
    xlabel="len(a)",
)

1
प्लॉट जनरेट करने के लिए कोड पोस्ट करने के लिए धन्यवाद। अब से पहले perfplot के बारे में पता नहीं था । हाथ लगता है।
रफ्सल

मैं विकल्प जोड़कर अपने कोड को चलाने के लिए सक्षम था equality_check=array_sorteqमें perfplot.show()। क्या एक त्रुटि पैदा कर रहा था pd.value_counts( अजगर 2 में) था (यहां तक ​​कि सॉर्ट = गलत के साथ)।
user2314737

33

पांडा मॉड्यूल का उपयोग करना:

>>> import pandas as pd
>>> import numpy as np
>>> x = np.array([1,1,1,2,2,2,5,25,1,1])
>>> pd.value_counts(x)
1     5
2     3
25    1
5     1
dtype: int64

5
pd.Series () आवश्यक नहीं है। अन्यथा, अच्छा उदाहरण। साथ ही गांठदार। पंडों इनपुट के रूप में एक साधारण सूची ले सकते हैं।
योहन ओबैदिया

1
@ योहनबादिया - सरणी के आकार के आधार पर, इसे पहली बार श्रृंखला में परिवर्तित करने से मेरे लिए अंतिम ऑपरेशन तेज हो गया है। मैं लगभग 50,000 मूल्यों के निशान का अनुमान लगाऊंगा।
n1k31t4

1
मैंने अपना उत्तर संपादित करने के लिए @YohanObadia
ivankeller

19

यह अब तक का सबसे सामान्य और अच्छा समाधान है; आश्चर्य है कि यह अभी तक पोस्ट नहीं किया गया है।

import numpy as np

def unique_count(a):
    unique, inverse = np.unique(a, return_inverse=True)
    count = np.zeros(len(unique), np.int)
    np.add.at(count, inverse, 1)
    return np.vstack(( unique, count)).T

print unique_count(np.random.randint(-10,10,100))

वर्तमान में स्वीकार किए गए उत्तर के विपरीत, यह किसी भी डेटाटाइप पर काम करता है जो कि छांटने योग्य (न केवल सकारात्मक ints) है, और इसका इष्टतम प्रदर्शन है; केवल महत्वपूर्ण व्यय np.unique द्वारा की गई छंटाई में है।


काम नहीं करता है:AttributeError: 'numpy.ufunc' object has no attribute 'at'
PR

कॉल करने के लिए एक सरल विधि होगीnp.bincount(inverse)
अली_m

15

numpy.bincountशायद सबसे अच्छा विकल्प है। यदि आपके सरणी में छोटे घने पूर्णांक के अलावा कुछ भी है तो इसे इस तरह से लपेटना उपयोगी हो सकता है:

def count_unique(keys):
    uniq_keys = np.unique(keys)
    bins = uniq_keys.searchsorted(keys)
    return uniq_keys, np.bincount(bins)

उदाहरण के लिए:

>>> x = array([1,1,1,2,2,2,5,25,1,1])
>>> count_unique(x)
(array([ 1,  2,  5, 25]), array([5, 3, 1, 1]))

8

भले ही यह पहले से ही उत्तर दे दिया गया हो, मैं एक अलग दृष्टिकोण का सुझाव देता हूं जिसका उपयोग किया जाता है numpy.histogram। इस तरह के फ़ंक्शन को एक अनुक्रम दिया जाता है, जो डिब्बे में रखे गए अपने तत्वों की आवृत्ति देता है

हालांकि खबरदार : यह इस उदाहरण में काम करता है क्योंकि संख्या पूर्णांक हैं। यदि वे वास्तविक संख्याएं हैं, तो यह समाधान अच्छी तरह से लागू नहीं होगा।

>>> from numpy import histogram
>>> y = histogram (x, bins=x.max()-1)
>>> y
(array([5, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       1]),
 array([  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,
        12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.,  21.,  22.,
        23.,  24.,  25.]))

5
import pandas as pd
import numpy as np
x = np.array( [1,1,1,2,2,2,5,25,1,1] )
print(dict(pd.Series(x).value_counts()))

यह आपको देता है: {1: 5, 2: 3, 5: 1, 25: 1}


1
collections.Counter(x)एक ही परिणाम भी दें। मेरा मानना ​​है कि ओपी एक आउटपुट चाहता है जो आर tableफ़ंक्शन जैसा दिखता है। रखना Seriesअधिक उपयोगी हो सकता है।
पाइलैंग

कृपया ध्यान दें कि pd.Series(x).reshape(-1)यदि यह एक बहुआयामी सरणी है, तो इसे स्थानांतरित करना आवश्यक होगा ।
नत्सापो

4

अद्वितीय गैर-पूर्णांक की गणना करने के लिए - इल्को होओगेन्डोर्न के उत्तर के समान लेकिन काफी तेज (मेरी मशीन पर 5 का कारक), मैं थोड़ा सी-कोड के साथ weave.inlineसंयोजन numpy.uniqueकरता था;

import numpy as np
from scipy import weave

def count_unique(datain):
  """
  Similar to numpy.unique function for returning unique members of
  data, but also returns their counts
  """
  data = np.sort(datain)
  uniq = np.unique(data)
  nums = np.zeros(uniq.shape, dtype='int')

  code="""
  int i,count,j;
  j=0;
  count=0;
  for(i=1; i<Ndata[0]; i++){
      count++;
      if(data(i) > data(i-1)){
          nums(j) = count;
          count = 0;
          j++;
      }
  }
  // Handle last value
  nums(j) = count+1;
  """
  weave.inline(code,
      ['data', 'nums'],
      extra_compile_args=['-O2'],
      type_converters=weave.converters.blitz)
  return uniq, nums

प्रोफ़ाइल जानकारी

> %timeit count_unique(data)
> 10000 loops, best of 3: 55.1 µs per loop

इल्को का शुद्ध numpyसंस्करण:

> %timeit unique_count(data)
> 1000 loops, best of 3: 284 µs per loop

ध्यान दें

यहां अतिरेक है ( uniqueएक प्रकार भी करता है), जिसका अर्थ है कि कोड को संभवतः uniqueसी-कोड लूप के अंदर कार्यक्षमता डालकर और अधिक अनुकूलित किया जा सकता है ।


4

पुराना प्रश्न है, लेकिन मैं अपना स्वयं का समाधान प्रदान करना चाहूंगा जो सबसे तेज़ हो, listइसके बजाय सामान्य का उपयोग करेंnp.array मेरे बेंच टेस्ट के आधार पर इनपुट (या पहली सूची में स्थानांतरण) के ।

यदि आपको इसका सामना करना पड़ता है, तो इसे देखें

def count(a):
    results = {}
    for x in a:
        if x not in results:
            results[x] = 1
        else:
            results[x] += 1
    return results

उदाहरण के लिए,

>>>timeit count([1,1,1,2,2,2,5,25,1,1]) would return:

100000 लूप्स, सर्वश्रेष्ठ 3: 2.26 ops प्रति लूप

>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]))

100000 लूप्स, सर्वश्रेष्ठ 3: 8.8 loops प्रति लूप

>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]).tolist())

100000 लूप्स, सर्वश्रेष्ठ 3: 5.85 .s प्रति लूप

जबकि स्वीकृत उत्तर धीमा होगा, और scipy.stats.itemfreqसमाधान भी बदतर है।


एक अधिक अदम्य परीक्षण ने तैयार की गई अपेक्षा की पुष्टि नहीं की

from zmq import Stopwatch
aZmqSTOPWATCH = Stopwatch()

aDataSETasARRAY = ( 100 * abs( np.random.randn( 150000 ) ) ).astype( np.int )
aDataSETasLIST  = aDataSETasARRAY.tolist()

import numba
@numba.jit
def numba_bincount( anObject ):
    np.bincount(    anObject )
    return

aZmqSTOPWATCH.start();np.bincount(    aDataSETasARRAY );aZmqSTOPWATCH.stop()
14328L

aZmqSTOPWATCH.start();numba_bincount( aDataSETasARRAY );aZmqSTOPWATCH.stop()
592L

aZmqSTOPWATCH.start();count(          aDataSETasLIST  );aZmqSTOPWATCH.stop()
148609L

संदर्भ। कैश पर टिप्पणी और अन्य-रैम साइड-इफेक्ट्स जो छोटे डेटासेट को बड़े पैमाने पर दोहराए जाने वाले परीक्षण परिणामों को प्रभावित करते हैं।


यह उत्तर वास्तव में अच्छा है, क्योंकि यह दर्शाता numpyहै कि जरूरी नहीं कि जाने का रास्ता हो।
महदी

@ रैन ली दिलचस्प। क्या आपने कुछ गैर-कैश-सक्षम डेटासेट आकार पर भी सूची-परिकल्पना को पार कर लिया है? एक प्रतिनिधित्व में 150.000 यादृच्छिक आइटम मान लेते हैं और aZmqStopwatch.start (); count (aRepresentation); aZmqStopwatch .stop () के उदाहरण के रूप में एकल रन पर थोड़ा अधिक सटीक मापा जाता है ।
user3666197

कुछ परीक्षण किए और हां, वास्तविक डेटासेट प्रदर्शन में भारी अंतर हैं । परीक्षण में अजगर आंतरिक यांत्रिकी में थोड़ी अधिक अंतर्दृष्टि की आवश्यकता होती है, बस एक पाशविक बल से चलने वाले छोरों को चलाने और गैर -इन-विट्रो नैनोसेकंड को गैर-यथार्थवादी । परीक्षण किया के रूप में - एक np.bincount () के भीतर 150.000 सरणी को संभालने के लिए बनाया जा सकता है कम से कम 600 [हमें] जबकि इसके बाद के संस्करण डीईएफ़ एड गिनती () एक पूर्व परिवर्तित सूची प्रतिनिधित्व पर उसके ले लिया और अधिक से अधिक 122.000 [हमें]
user3666197

हाँ, मेरा नियम कुछ भी ऐसा नहीं है जिसके लिए थोड़ी मात्रा में विलंबता को नियंत्रित किया जा सके, लेकिन इसमें बहुत बड़ी होने की संभावना है, छोटे डेटा सेटों की सूची जहां विलंबता महत्वपूर्ण है, और निश्चित रूप से वास्तविक बेंचमार्किंग FTW :)
डेविड

1

इस तरह से कुछ करना चाहिए:

#create 100 random numbers
arr = numpy.random.random_integers(0,50,100)

#create a dictionary of the unique values
d = dict([(i,0) for i in numpy.unique(arr)])
for number in arr:
    d[j]+=1   #increment when that value is found

इसके अलावा, कुशल तत्वों की गणना करने वाली यह पिछली पोस्ट आपके प्रश्न के समान सुंदर लगती है, जब तक कि मुझे कुछ याद न हो।


जुड़ा हुआ सवाल थोड़े समान है, लेकिन ऐसा लगता है कि वह अधिक जटिल डेटा प्रकारों के साथ काम कर रहा है।
अबे

1

मल्टी-डिमेंशनल फ्रीक्वेंसी काउंट, यानी गिनती सरणियाँ।

>>> print(color_array    )
  array([[255, 128, 128],
   [255, 128, 128],
   [255, 128, 128],
   ...,
   [255, 128, 128],
   [255, 128, 128],
   [255, 128, 128]], dtype=uint8)


>>> np.unique(color_array,return_counts=True,axis=0)
  (array([[ 60, 151, 161],
    [ 60, 155, 162],
    [ 60, 159, 163],
    [ 61, 143, 162],
    [ 61, 147, 162],
    [ 61, 162, 163],
    [ 62, 166, 164],
    [ 63, 137, 162],
    [ 63, 169, 164],
   array([     1,      2,      2,      1,      4,      1,      1,      2,
         3,      1,      1,      1,      2,      5,      2,      2,
       898,      1,      1,  


0
from collections import Counter
x = array( [1,1,1,2,2,2,5,25,1,1] )
mode = counter.most_common(1)[0][0]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.