web-dev-qa-db-fra.com

Comment extraire des nombres (avec des adjectifs ou des plages de comparaison)

Je travaille sur deux projets NLP en Python, et les deux ont une tâche similaire pour extraire des valeurs numériques et des opérateurs de comparaison à partir de phrases, comme suit:

"... greater than $10 ... ",
"... weight not more than 200lbs ...",
"... height in 5-7 feets ...",
"... faster than 30 seconds ... "

J'ai trouvé deux approches différentes pour résoudre ce problème:

  • en utilisant des expressions régulières très complexes.
  • en utilisant Named Entity Recognition (et quelques regex aussi).

Comment puis-je analyser des valeurs numériques à partir de ces phrases? Je suppose que c'est une tâche courante en PNL.


La sortie souhaitée serait quelque chose comme:

Entrée:

"supérieur à 10 $"

Sortie:

{'value': 10, 'unit': 'dollar', 'relation': 'gt', 'position': 3}
34
svfat

J'aborderais probablement cela comme une tâche de segmentation et utiliserais la partie de nltk du marqueur de discours combinée avec son fragment d'expression régulière. Cela vous permettra de définir une expression régulière basée sur la partie du discours des mots dans vos phrases plutôt que sur les mots eux-mêmes. Pour une phrase donnée, vous pouvez effectuer les opérations suivantes:

import nltk

# example sentence
sent = 'send me a table with a price greater than $100'

La première chose que je ferais est de modifier légèrement vos phrases afin de ne pas trop confondre la partie du tagueur de discours. Voici quelques exemples de modifications que vous pouvez apporter (avec des expressions régulières très simples) mais vous pouvez expérimenter et voir s'il y en a d'autres:

$10 -> 10 dollars
200lbs -> 200 lbs
5-7 -> 5 - 7 OR 5 to 7

nous obtenons donc:

sent = 'send me a table with a price greater than 100 dollars'

vous pouvez maintenant obtenir les parties du discours de votre phrase:

sent_pos = nltk.pos_tag(sent.split())
print(sent_pos)

[('send', 'VB'), ('me', 'PRP'), ('a', 'DT'), ('table', 'NN'), ('with', 'IN'), ('a', 'DT'), ('price', 'NN'), ('greater', 'JJR'), ('than', 'IN'), ('100', 'CD'), ('dollars', 'NNS')]

Nous pouvons maintenant créer un chunker qui fragmentera votre texte balisé POS selon une expression régulière (relativement) simple:

grammar = 'NumericalPhrase: {<NN|NNS>?<RB>?<JJR><IN><CD><NN|NNS>?}'
parser = nltk.RegexpParser(grammar)

Cela définit un analyseur avec une grammaire qui fragmente les phrases numériques (ce que nous appellerons votre type de phrase). Il définit votre phrase numérique comme: un nom facultatif, suivi d'un adverbe facultatif, suivi d'un adjectif comparatif, d'une préposition, d'un nombre et d'un nom facultatif. Ceci est juste une suggestion sur la façon dont vous voudrez peut-être définir vos phrases, mais je pense que ce sera beaucoup plus simple que d'utiliser une expression régulière sur les mots eux-mêmes.

Pour obtenir vos phrases, vous pouvez faire:

print(parser.parse(sent_pos))
(S
  send/VB
  me/PRP
  a/DT
  table/NN
  with/IN
  a/DT
  (NumericalPhrase price/NN greater/JJR than/IN 100/CD dollars/NNS))  

Ou pour obtenir uniquement vos phrases, vous pouvez faire:

print([tree.leaves() for tree in parser.parse(sent_pos).subtrees() if tree.label() == 'NumericalPhrase'])

[[('price', 'NN'),
  ('greater', 'JJR'),
  ('than', 'IN'),
  ('100', 'CD'),
  ('dollars', 'NNS')]]
31
bunji