J'ai des listes 2D avec chaque ligne contenant des entrées COMMON_NAME et des informations supplémentaires. Je veux trouver la somme du nombre d'éléments MYFR appartenant à chaque 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']
Pour chaque COMMOM_NAME, je veux trouver la somme des occurrences si elles sont dans {'MYFR01', 'MYFR02', 'MYFR03'}
Telles que dans cet exemple je veux obtenir COMMON_NAME1 = 3 et COMMON_NAME2 = 2
Existe-t-il un moyen simple d'y parvenir?
Merci
3 Réponses :
Voici une solution avec collections.Counter:
>>> 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})
Cela suppose que vos choix de cibles commenceront toujours par MYFR . En lisant un peu plus attentivement votre question, vous pouvez également utiliser:
>>> 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})
La bonne chose à propos de Counter (une sous-classe de dict ) est qu'il peut accepter un expression du générateur . Cela signifie que vous n'avez pas besoin de matérialiser les éléments "filtrés" dans une structure de données intermédiaire telle qu'une liste.
L'exécution de ces deux solutions donne une valeur à Counter () avec len = 0 sur mon python 3.7. Y a-t-il quelque chose qui me manque?
Peu importe, c'était juste la valeur de décalage incorrecte. Merci
Nous allons garder un dictionnaire mappant les valeurs de COMMON_NAME à des ensembles de valeurs MYFR , puis mesurer la taille de ces ensembles à la fin. Cela détermine le nombre d'éléments uniques MYFR pour chaque 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}
Vous pouvez également utiliser pandas pour cela:
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
De plus, nous pouvons utiliser itertools:
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
La seule mise en garde ici est que les données doivent d'abord être triées.