Вычислить количество всех элементов во вложенном списке
у меня есть список списков и я хотел бы создать фрейм данных с количеством всех уникальных элементов. Вот мои тестовые данные:
test = [["P1", "P1", "P1", "P2", "P2", "P1", "P1", "P3"],
["P1", "P1", "P1"],
["P1", "P1", "P1", "P2"],
["P4"],
["P1", "P4", "P2"],
["P1", "P1", "P1"]]
Я могу сделать что-то вроде этого, используя Counter
С for
цикл as:
from collections import Counter
for item in test:
print(Counter(item))
но как я могу получить результат этого цикла, суммированного в новый фрейм данных ?
ожидаемый вывод в виде фрейма данных:
P1 P2 P3 P4
15 4 1 2
4 ответов
вот один из способов.
from collections import Counter
from itertools import chain
test = [["P1", "P1", "P1", "P2", "P2", "P1", "P1", "P3"],
["P1", "P1", "P1"],
["P1", "P1", "P1", "P2"],
["P4"],
["P1", "P4", "P2"],
["P1", "P1", "P1"]]
c = Counter(chain.from_iterable(test))
for k, v in c.items():
print(k, v)
# P1 15
# P2 4
# P3 1
# P4 2
для вывода в виде фрейма данных:
df = pd.DataFrame.from_dict(c, orient='index').transpose()
# P1 P2 P3 P4
# 0 15 4 1 2
С точки зрения лучшей производительности, вы должны использовать:
-
collections.Counter
Сitertools.chain.from_iterable
as:>>> from collections import Counter >>> from itertools import chain >>> Counter(chain.from_iterable(test)) Counter({'P1': 15, 'P2': 4, 'P4': 2, 'P3': 1})
-
или, yo должен использовать
collections.Counter
С понимание (требует меньше импортаitertools
С такой же производительностью) as:>>> from collections import Counter >>> Counter([x for a in test for x in a]) Counter({'P1': 15, 'P2': 4, 'P4': 2, 'P3': 1})
продолжайте читать для более альтернативных решений и сравнение производительности. (скип иное)
подход 1: объедините свои подсписки, чтобы создать единый list
и найти счет, используя collections.Counter
.
-
Решение 1: конкатенация списка с помощью
itertools.chain.from_iterable
и найти счет, используяcollections.Counter
as:test = [ ["P1", "P1", "P1", "P2", "P2", "P1", "P1", "P3"], ["P1", "P1", "P1"], ["P1", "P1", "P1", "P2"], ["P4"], ["P1", "P4", "P2"], ["P1", "P1", "P1"] ] from itertools import chain from collections import Counter my_counter = Counter(chain.from_iterable(test))
-
решение 2: объединить список с помощью понимание as:
from collections import Counter my_counter = Counter([x for a in my_list for x in a])
-
решение 3: конкатенация списка с помощью
sum
from collections import Counter my_counter = Counter(sum(test, []))
подход 2: вычислить количество элементов в каждом подсписке с помощью collections.Counter
и затем sum
the Counter
объекты в списке.
-
решение 4: подсчет объектов каждого подсписка с помощью
collections.Counter
иmap
as:from collections import Counter my_counter = sum(map(Counter, test), Counter())
-
решение 5: подсчет объектов каждого подсписка с помощью понимание as:
from collections import Counter my_counter = sum([Counter(t) for t in test], Counter())
во всех решениях выше,my_counter
проведет значение:
>>> my_counter
Counter({'P1': 15, 'P2': 4, 'P4': 2, 'P3': 1})
Сравнение Производительности
ниже timeit
сравнение на Python 3 для списка 1000 подсписок и 100 элементов в каждом подсписке:
-
быстрый, используя
chain.from_iterable
(17.1 мсек)mquadri$ python3 -m timeit "from collections import Counter; from itertools import chain; my_list = [list(range(100)) for i in range(1000)]" "Counter(chain.from_iterable(my_list))" 100 loops, best of 3: 17.1 msec per loop
-
второй в списке использует понимание чтобы объединить список, а затем сделать
Count
(аналогичный результат, как указано выше, но без дополнительный импортitertools
) (18.36 msec)mquadri$ python3 -m timeit "from collections import Counter; my_list = [list(range(100)) for i in range(1000)]" "Counter([x for a in my_list for x in a])" 100 loops, best of 3: 18.36 msec per loop
-
третий с точки зрения производительности является использование
Counter
по подспискам внутри понимание : (162 МС)mquadri$ python3 -m timeit "from collections import Counter; my_list = [list(range(100)) for i in range(1000)]" "sum([Counter(t) for t in my_list], Counter())" 10 loops, best of 3: 162 msec per loop
-
четвертым в списке является использование
Counter
Сmap
(результаты очень похожи на тот, который использует понимание выше) (176 msec)mquadri$ python3 -m timeit "from collections import Counter; my_list = [list(range(100)) for i in range(1000)]" "sum(map(Counter, my_list), Counter())" 10 loops, best of 3: 176 msec per loop
-
решение с помощью
sum
для объединения списка слишком медленно (526 МС)mquadri$ python3 -m timeit "from collections import Counter; my_list = [list(range(100)) for i in range(1000)]" "Counter(sum(my_list, []))" 10 loops, best of 3: 526 msec per loop
вот еще один способ сделать это, используя itertools.groupby
>>> from itertools import groupby, chain
>>> out = [(k,len(list(g))) for k,g in groupby(sorted(chain(*test)))]
>>> out
>>> [('P1', 15), ('P2', 4), ('P3', 1), ('P4', 2)]
преобразовать его в dict, как:
>>> dict(out)
>>> {'P2': 4, 'P3': 1, 'P1': 15, 'P4': 2}
чтобы преобразовать его в dataframe используйте
>>> import pandas as pd
>>> pd.DataFrame(dict(out), index=[0])
P1 P2 P3 P4
0 15 4 1 2
функция " set " сохраняет только уникальные элементы в списке. Таким образом, используя "len(set(mylinst))", вы получаете количество уникальных элементов в своем списке. Тогда вам нужно только повторить это.
dict_nb_item = {}
i = 0
for test_item in test:
dict_nb_item[i] = len(set(test_item))
i += 1
print(dict_nb_item)