1
votes

Méthode pythonique pour analyser les tuples

Je travaille avec une liste de tuples, comme ci-dessous:

29
7
22
5

Je recherche une sortie qui affichera le nombre de noms, verbes, adjectifs et autres mots dans cette liste de tuples, avec les critères suivants:

  • Un nom commence par NN
  • Un verbe commence par VB ou VP
  • Un adjectif commence par JJ
  • Autre ne répond pas à ces critères

Jusqu'à présent, j'ai:

cnts = [cnt_noun, cnt_vb, cnt_adj, cnt_other]
for x in cnts:
    print(x)

Et cela affiche correctement les décomptes:

# Create a set of all values that appear
appears = set([x[1] for x in res])

cnt_noun = 0
cnt_adj = 0
cnt_vb = 0
cnt_other = 0

for tpl in res:
    if('NN' in tpl[1]):
        cnt_noun += 1
    elif('JJ' in tpl[1]):
        cnt_adj += 1
    elif('VB' in tpl[1] or 'VP' in tpl[1]):
        cnt_vb += 1
    else:
        cnt_other += 1

Rendements

res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig', 'JJ'), ('start', 'NN'), ('open', 'JJ'), ('scene', 'NN'), ('terrif', 'NN'), ('exampl', 'NN'), ('absurd', 'JJ'), ('comedi', 'NN'), ('formal', 'JJ'), ('orchestra', 'NN'), ('audienc', 'NN'), ('turn', 'VBP'), ('insan', 'JJ'), ('violent', 'JJ'), ('mob', 'NN'), ('crazi', 'NN'), ('chant', 'JJ'), ('singer', 'NN'), ('unfortun', 'JJ'), ('stay', 'NN'), ('absurd', 'IN'), ('whole', 'JJ'), ('time', 'NN'), ('general', 'JJ'), ('narrat', 'NN'), ('eventu', 'VBP'), ('make', 'VBP'), ('put', 'VB'), ('even', 'RB'), ('era', 'NN'), ('turn', 'NN'), ('cryptic', 'JJ'), ('dialogu', 'NN'), ('would', 'MD'), ('make', 'VB'), ('shakespear', 'JJ'), ('seem', 'JJ'), ('easi', 'JJ'), ('third', 'JJ'), ('grader', 'NN'), ('technic', 'JJ'), ('level', 'NN'), ('better', 'RBR'), ('might', 'MD'), ('think', 'VB'), ('good', 'JJ'), ('cinematographi', 'NN'), ('futur', 'NN'), ('great', 'JJ'), ('vilmo', 'JJ'), ('zsigmond', 'NN'), ('futur', 'NN'), ('star', 'NN'), ('salli', 'NN'), ('kirkland', 'NN'), ('freder', 'NN'), ('forrest', 'JJS'), ('seen', 'VBN'), ('briefli', 'NN')]

Il est important de renvoyer les décomptes de chaque balise de mot dans sa totalité, car cela sera utilisé dans le cadre d'une grande séquence de construction de données.

Cependant, y a-t-il une manière plus pythonique d'accomplir la même chose, avec moins de lignes et plus efficacement?


4 commentaires

Vous souciez-vous de la sortie intermédiaire comme print ("Verb: {}". Format (tpl)) ?


@HansMusgrave franchement pas tellement, était là plus pour s'assurer que le code fonctionnait correctement, je devrais le supprimer.


En utilisant elif ('VB' dans tpl [1] ou 'VP' dans tpl [1]): , vous comptez pour 'VBP' , 'VBN ' aussi. Est-ce prévu?


@Austin oui, car les deux commencent VB et / ou VP . La séquence de caractères restante n'est pas pertinente; c'est ce par quoi il commence qui est important.


3 Réponses :


5
votes

J'utiliserais probablement des collections.Counter:

from collections import Counter

res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig', 'JJ'), ('start', 'NN'), ('open', 'JJ'), ('scene', 'NN'), ('terrif', 'NN'), ('exampl', 'NN'), ('absurd', 'JJ'), ('comedi', 'NN'), ('formal', 'JJ'), ('orchestra', 'NN'), ('audienc', 'NN'), ('turn', 'VBP'), ('insan', 'JJ'), ('violent', 'JJ'), ('mob', 'NN'), ('crazi', 'NN'), ('chant', 'JJ'), ('singer', 'NN'), ('unfortun', 'JJ'), ('stay', 'NN'), ('absurd', 'IN'), ('whole', 'JJ'), ('time', 'NN'), ('general', 'JJ'), ('narrat', 'NN'), ('eventu', 'VBP'), ('make', 'VBP'), ('put', 'VB'), ('even', 'RB'), ('era', 'NN'), ('turn', 'NN'), ('cryptic', 'JJ'), ('dialogu', 'NN'), ('would', 'MD'), ('make', 'VB'), ('shakespear', 'JJ'), ('seem', 'JJ'), ('easi', 'JJ'), ('third', 'JJ'), ('grader', 'NN'), ('technic', 'JJ'), ('level', 'NN'), ('better', 'RBR'), ('might', 'MD'), ('think', 'VB'), ('good', 'JJ'), ('cinematographi', 'NN'), ('futur', 'NN'), ('great', 'JJ'), ('vilmo', 'JJ'), ('zsigmond', 'NN'), ('futur', 'NN'), ('star', 'NN'), ('salli', 'NN'), ('kirkland', 'NN'), ('freder', 'NN'), ('forrest', 'JJS'), ('seen', 'VBN'), ('briefli', 'NN')]
mapping = {'NN':'noun', 'JJ':'adjective','VB':'verb','VP':'verb'}
counter = Counter([mapping.get(b[:2], "other") for a, b in res])
print(counter)  # Counter({'noun': 29, 'adjective': 22, 'verb': 7, 'other': 5})

Voici une solution complète:

res = [('stori', 'JJ'), ('man', 'NN'), ...]
counter = Counter([b for a, b in res])
# Counter acts like a dictionary containing e.g. {'JJ': 3, ...}


5 commentaires

Pas le downvoter, probablement pas le résultat attendu.


Je n'ai pas non plus voté contre, mais cela ne correspond pas au résultat attendu.


Je comprends que cela ne correspond pas à la sortie bien que je pense que c'est la première étape pour l'OP


Le code que j'ai posté produit le résultat attendu, c'est franchement inefficace et non pythonique. Mais, c'est quelque chose à examiner certainement, merci.


@wwii Si vous relisez le code d'OP, ce n'est pas exactement ce que OP veut.



1
votes

Vous pouvez utiliser collections.defaultdict et le rendre plus propre:

Adj 22
Noun 29
Verb 7
Others 5

Quelles sorties:

d = defaultdict(list)

for x, y in res:
    if 'VB' in y or 'VP' in y:
        y = 'Verb'
    elif 'JJ' in y:
        y = 'Adj'     
    elif 'NN' in y:
        y = 'Noun'
    else:
        y = 'Others'

    d[y].append(x)

        
for k, v in d.items():
    print(k, len(v))

p >


0 commentaires

3
votes

collections.Counter est la voie à suivre.

  • Créez un dictionnaire mappant les chaînes de deux caractères à leurs classifications .
  • Utilisez le deuxième élément de chaque tuple pour rechercher les valeurs dans ce dictionnaire, la méthode get retournera 'other' pour tout ce qui n'est pas défini.
  • Transmettez les valeurs aux collections.Counter.

>>> c
Counter({'noun': 29, 'adjective': 22, 'verb': 7, 'other': 5})
>>>

En tant que boucle for:

c = collections.Counter()
for word,quality in res:
    c.update(stuff.get(quality[:2],'other'))

import collections
stuff = {'NN':'noun', 'JJ':'adjective','VB':'verb','VP':'verb'}
c = collections.Counter(stuff.get(thing[:2],'other') for word,thing in res)


0 commentaires