У меня есть данные, которые находятся в диапазоне 1-100. Я хочу получить количество этих данных в следующих диапазонах. Допустим, у меня есть эти данные: [17, 30, 62 65, 92, 95, 98]. Я хочу получить это:

00-10: 0
11-20: 1
21-30: 1
31-40: 0
41:50: 0
51:60: 0
61:70: 2
71:80: 0
81:90: 0
91:100: 3

Интересно, есть ли функция pandas / numpy / scipy для достижения этой скорости? Я ценю любую помощь!

4
renakre 9 Янв 2017 в 13:01

6 ответов

Лучший ответ

Вы можете использовать cut с value_counts:

bins = np.arange(0,110,10)
s = pd.Series([17, 30, 62, 65, 92, 95, 98])
s1 = pd.cut(s, bins=bins)
print (s1.value_counts(sort=False))
(0, 10]      0
(10, 20]     1
(20, 30]     1
(30, 40]     0
(40, 50]     0
(50, 60]     0
(60, 70]     2
(70, 80]     0
(80, 90]     0
(90, 100]    3
dtype: int64
5
jezrael 9 Янв 2017 в 10:05

Вы можете достичь этого с помощью встроенного bisect модуля следующим образом:

from bisect import bisect

my_list = [17, 30, 62, 65, 92, 95, 98]  # sort it if not already sorted
my_interval = list(range(0, 101, 10))

new_list = [((i+1, j), len(my_list[bisect(my_list, i+1):bisect(my_list, j)])) \
    for i, j in zip(my_interval, my_interval[1:])]

Окончательное значение hold будет new_list будет:

[((0, 10), 0), ((10, 20), 1), ((20, 30), 1), ((30, 40), 0), ((40, 50), 0), ((50, 60), 0), ((60, 70), 2), ((70, 80), 0), ((80, 90), 0), ((90, 100), 3)]

Чтобы напечатать значения в нужном формате, вы делаете:

for (i, j), val in new_list:
    print '{}-{}: {}'.format(i, j, val)

Который напечатает:

1-10: 0
11-20: 1
21-30: 1
31-40: 0
41-50: 0
51-60: 0
61-70: 2
71-80: 0
81-90: 0
91-100: 3
2
Moinuddin Quadri 9 Янв 2017 в 10:19
import numpy as np
# use np.where or np.nonzero for indices and np.logical_and to set alpha/omega
a = np.array([17, 30, 62, 65, 92, 95, 98])

for n in range(0,100,10):
  b = a[np.where(np.logical_and(a>=n, a<=n+10))]
  c = a[np.nonzero(np.logical_and(a>=n, a<=n+10))]
  print ((n, n+10), len(b), len(c), b, c)

(0, 10) 0 0 [] []
(10, 20) 1 1 [17] [17]
(20, 30) 1 1 [30] [30]
(30, 40) 1 1 [30] [30]
(40, 50) 0 0 [] []
(50, 60) 0 0 [] []
(60, 70) 2 2 [62 65] [62 65]
(70, 80) 0 0 [] []
(80, 90) 0 0 [] []
(90, 100) 3 3 [92 95 98] [92 95 98]
2
Ari Gold 9 Янв 2017 в 10:23

Непустое решение, возможно, оно будет выглядеть неубедительным ... Использование collections.Counter и округление:

from collections import Counter

a = [ 10,11,17, 30, 62, 65, 92, 95, 98,100]

# directly count using a generator comprehension instead of a loop
c = Counter(((i-1)//10)*10 for i in a)


for i in range(0,((max(a)+1)*10)//10,10):
    print("{}-{}: {}".format(i+1,i+10,c[i] if i in c else 0))

В основном, считая каждое вхождение, а затем выведите все значения или 0, если их нет в словаре: обратите внимание, что это не счет 0 или отрицательных чисел.

Результат (изменил входные данные и границы, добавив 1, потому что это было неоднозначно):

1-10: 1
11-20: 2
21-30: 1
31-40: 0
41-50: 0
51-60: 0
61-70: 2
71-80: 0
81-90: 0
91-100: 4
101-110: 0
2
Jean-François Fabre 9 Янв 2017 в 17:39

Это всего лишь гистограмма, поэтому np.histogram(data, np.arange(0,101,10))[0]

5
Daniel F 9 Янв 2017 в 10:27

Это можно сделать с помощью numpy.digitize и поместить этот вывод в numpy.bincount,

Примере:

import numpy as np

a = np.array([9, 17, 30, 62, 65, 92, 95, 98])

bins = np.arange(0, 100, 10)
inds = np.digitize(a, bins) - 1

counts  = np.bincount(inds)
for r, count in zip(bins, counts):
    print((r, r+10), count)

Это возвращает желаемый результат. Цифровая цифра в основном говорит вам, где ваш номер должен быть вставлен в монотонно увеличивающемся или уменьшающемся массиве. Если вы тогда рассчитываете, что вы получите количество на раздел. Потому что np.digitize возвращает i так, что bins[i-1] <= x < bins[i] вам нужно вычесть единицу, чтобы получить первое значение для первого бина (бин 0).

2
xyzzyqed 9 Янв 2017 в 12:41