Счетчик элементов списка - PullRequest
       6

Счетчик элементов списка

0 голосов
/ 18 февраля 2019

Новый для Python здесь.

Я ищу простой способ создания списка (Вывод), который возвращает количество элементов другого списка целей (MyList) при сохранении индексации (?).

Вот что я хотел бы получить:

MyList = ["a", "b", "c", "c", "a", "c"]
Output = [ 2 ,  1 ,  3 ,  3 ,  2 ,  3 ]

Я нашел решение аналогичной проблемы.Подсчитайте количество вхождений для каждого элемента в списке.

In  : Counter(MyList)
Out : Counter({'a': 2, 'b': 1, 'c': 3})

Это, однако, возвращает объект Counter, который не сохраняет индексацию.

Я предполагаю, что с учетом ключей вСчетчик Я мог бы построить желаемый вывод, однако я не уверен, как действовать.

Дополнительная информация, в моем скрипте импортированы панды, а MyList фактически является столбцом в фрейме данных панд.

Ответы [ 7 ]

0 голосов
/ 18 февраля 2019

Используйте np.unique, чтобы создать словарь подсчета значений и отобразить значения.Это будет быстро, но не так быстро, как методы Счетчика:

import numpy as np

list(map(dict(zip(*np.unique(MyList, return_counts=True))).get, MyList))
#[2, 1, 3, 3, 2, 3]

Некоторые временные интервалы для списка среднего размера:

MyList = np.random.randint(1, 2000, 5000).tolist()

%timeit [MyList.count(i) for i in MyList]
#413 ms ± 165 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit list(map(dict(zip(*np.unique(MyList, return_counts=True))).get, MyList))
#1.89 ms ± 1.73 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit pd.DataFrame(MyList).groupby(MyList).transform(len)[0].tolist()
#2.18 s ± 12.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

c=Counter(MyList)
%timeit lout=[c[i] for i in MyList]
#679 µs ± 2.33 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

c = Counter(MyList)
%timeit list(itemgetter(*MyList)(c))
#503 µs ± 162 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Большой список:

MyList = np.random.randint(1, 2000, 50000).tolist()

%timeit [MyList.count(i) for i in MyList]
#41.2 s ± 5.27 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit list(map(dict(zip(*np.unique(MyList, return_counts=True))).get, MyList))
#18 ms ± 56.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit pd.DataFrame(MyList).groupby(MyList).transform(len)[0].tolist()
#2.44 s ± 12.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

c=Counter(MyList)
%timeit lout=[c[i] for i in MyList]
#6.89 ms ± 22.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

c = Counter(MyList)
%timeit list(itemgetter(*MyList)(c))
#5.27 ms ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
0 голосов
/ 10 мая 2019

Обратите внимание, что в @Gio указывалось, что список был объектом Серии Панд.В этом случае вы можете преобразовать объект Series в список:

import pandas as pd

l = ["a", "b", "c", "c", "a", "c"]
ds = pd.Series(l) 
l=ds.tolist()
[l.count(i) for i in ds] 
# [2, 1, 3, 3, 2, 3]

Но, получив серию, вы можете считать элементы с помощью value_counts.

l = ["a", "b", "c", "c", "a", "c"]
s = pd.Series(l) #Series object
c=s.value_counts() #c is Series again
[c[i] for i in s] 
# [2, 1, 3, 3, 2, 3]
0 голосов
/ 18 февраля 2019

Решение для панд выглядит следующим образом:

df = pd.DataFrame(data=["a", "b", "c", "c", "a", "c"], columns=['MyList'])
df['Count'] = df.groupby('MyList')['MyList'].transform(len)

Редактировать : Нельзя использовать панд, если это единственное, что вы хотите сделать.Я только ответил на этот вопрос из-за тега панд.

Производительность зависит от количества групп:

MyList = np.random.randint(1, 10, 10000).tolist()
df = pd.DataFrame(MyList)

%timeit [MyList.count(i) for i in MyList]
# 1.32 s ± 15.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit df.groupby(0)[0].transform(len)
# 3.89 ms ± 112 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

MyList = np.random.randint(1, 9000, 10000).tolist()
df = pd.DataFrame(MyList)

%timeit [MyList.count(i) for i in MyList]
# 1.36 s ± 11.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit df.groupby(0)[0].transform(len)
# 1.33 s ± 19.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
0 голосов
/ 18 февраля 2019

Это один из классических фрагментов Хеттингера:)

from collections import Counter, OrderedDict

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first seen'
     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__,
                            OrderedDict(self))
     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

x = ["a", "b", "c", "c", "a", "c"]
oc = OrderedCounter(x)
>>> oc
OrderedCounter(OrderedDict([('a', 2), ('b', 1), ('c', 3)]))
>>> oc['a']
2
0 голосов
/ 18 февраля 2019

Вместо listcomp, как в другом решении, вы можете использовать функцию itemgetter():

from collections import Counter
from operator import itemgetter

MyList = ["a", "b", "c", "c", "a", "c"]

c = Counter(MyList)
itemgetter(*MyList)(c)
# (2, 1, 3, 3, 2, 3)

ОБНОВЛЕНИЕ: Как упоминалось в комментариях @ALollz, это решение кажется самым быстрым.Если OP нужен список вместо кортежа, результат должен быть преобразован с list().

0 голосов
/ 18 февраля 2019

Вам просто нужно реализовать приведенный ниже фрагмент кода

    c=Counter(MyList)
    lout=[c[i] for i in MyList]

Теперь список lout - ваш желаемый вывод

0 голосов
/ 18 февраля 2019

Вы можете использовать метод list.count, который будет подсчитывать количество раз, которое каждая строка имеет место в MyList.Вы можете создать новый список с подсчетами, используя понимание списка :

MyList = ["a", "b", "c", "c", "a", "c"]

[MyList.count(i) for i in MyList]
# [2, 1, 3, 3, 2, 3]
...