Подсчет появления нескольких элементов для определенного главного элемента в 2D-массиве с использованием Python - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть 2D списки с каждой строкой, содержащей записи COMMON_NAME и дополнительную информацию.Я хочу узнать, сколько элементов MYFR принадлежит каждому COMMON_NAME.

For example, this is my list 
[['SOME TEXT', 'COMMON_NAME1', None, 'CHOC', 'MYFR01'],
['SOME TEXT2', 'COMMON_NAME1', None, 'ABC',  'MYFR02'], 
['SOME TEXT3', 'COMMON_NAME1', None, 'XYZ',  'MYFR03'],
['SOME TEXT4', 'COMMON_NAME2', None, 'XYZ',  'STRAWBERRY'],
['SOME TEXT5', 'COMMON_NAME2', None, 'XYZ',  'MYFR01'],
['SOME TEXT6', 'COMMON_NAME2', None, 'XYZ',  'MYFR02'],
['SOME TEXT7', 'COMMON_NAME2', None, 'XYZ',  'APPLE'] 

Для каждого COMMOM_NAME я хочу найти сумму вхождений, если они находятся в {'MYFR01', 'MYFR02', 'MYFR03'}

Так, что в этом примере Iхотите получить COMMON_NAME1 = 3 и COMMON_NAME2 = 2

Есть ли простой способ добиться этого?

Спасибо

Ответы [ 3 ]

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

Мы будем хранить словарь, отображающий значения COMMON_NAME на наборы значений MYFR, а затем измерять размер этих наборов в конце.Это определяет количество уникальных MYFR элементов для каждого COMMON_NAME.

from collections import defaultdict

d = defaultdict(set)

for first, common_name, *others, last in my_list:
    if common_name.startswith("COMMON_NAME"):  # Maybe unneccessary
        if last.startswith("MYFR"):
            d[common_name].add(last)

d = {k: len(v) for k, v in d.items()}
# {'COMMON_NAME1': 3, 'COMMON_NAME2': 2}
0 голосов
/ 14 февраля 2019

Вы также можете использовать pandas для этого:

import pandas as pd

df = pd.DataFrame(data, columns=['text', 'cname', 'none', 'code', 'name'])

         text         cname  none  code        name
0   SOME TEXT  COMMON_NAME1  None  CHOC      MYFR01
1  SOME TEXT2  COMMON_NAME1  None   ABC      MYFR02
2  SOME TEXT3  COMMON_NAME1  None   XYZ      MYFR03
3  SOME TEXT4  COMMON_NAME2  None   XYZ  STRAWBERRY
4  SOME TEXT5  COMMON_NAME2  None   XYZ      MYFR01
5  SOME TEXT6  COMMON_NAME2  None   XYZ      MYFR02
6  SOME TEXT7  COMMON_NAME2  None   XYZ       APPLE


df.loc[df['name'].str.contains('MYFR'), ['name', 'cname']] \
  .groupby('cname', as_index=False) \
  .count()

          cname  name
0  COMMON_NAME1     3
1  COMMON_NAME2     2

Кроме того, мы можем использовать itertools:

from itertools import groupby

second = itemgetter(1)
last = itemgetter(-1)

for k, v in groupby(data, key=second):
    print(k, len([last(i) for i in v if last(i).startswith('MYFR')]))

COMMON_NAME1 3
COMMON_NAME2 2

Единственное предостережение здесь заключается в том, что данные должны быть отсортированы первыми.

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

Вот решение с collections.Counter:

>>> from collections import Counter
>>> data = [['SOME TEXT', 'COMMON_NAME1', None, 'CHOC', 'MYFR01'],
... ['SOME TEXT2', 'COMMON_NAME1', None, 'ABC',  'MYFR02'], 
... ['SOME TEXT3', 'COMMON_NAME1', None, 'XYZ',  'MYFR03'],
... ['SOME TEXT4', 'COMMON_NAME2', None, 'XYZ',  'STRAWBERRY'],
... ['SOME TEXT5', 'COMMON_NAME2', None, 'XYZ',  'MYFR01'],
... ['SOME TEXT6', 'COMMON_NAME2', None, 'XYZ',  'MYFR02'],
... ['SOME TEXT7', 'COMMON_NAME2', None, 'XYZ',  'APPLE']]

>>> c = Counter(i[1] for i in data if i[-1].startswith('MYFR'))
>>> c
Counter({'COMMON_NAME1': 3, 'COMMON_NAME2': 2})

Это предполагает, что ваш целевой выбор всегда будет начинаться с MYFR.Читая ваш вопрос немного более подробно, вы также можете использовать:

>>> tgt = {'MYFR01', 'MYFR02', 'MYFR03'}
>>> c = Counter(i[1] for i in data if i[-1] in tgt)
>>> c
Counter({'COMMON_NAME1': 3, 'COMMON_NAME2': 2})

Приятная вещь о Counter (подкласс dict) в том, что он может принимать генератор выражений .Это означает, что вам не нужно материализовать «отфильтрованные» элементы в некоторую промежуточную структуру данных, такую ​​как список.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...