2
votes

Bigram Finder pour Pandas Dataframe

J'ai une liste de bigrammes.
J'ai un dataframe pandas contenant une ligne pour chaque document de mon corpus. Ce que je cherche à faire, c'est obtenir les bigrammes qui correspondent à ma liste dans chaque document dans une nouvelle colonne de mon dataframe. Quelle est la meilleure façon d'accomplir cette tâche? J'ai cherché des réponses sur le débordement de pile, mais je n'ai pas trouvé quelque chose qui me donne une réponse spécifique que je recherche. J'ai besoin que la nouvelle colonne contienne tous les bigrammes trouvés dans ma liste de bigrammes.

Toute aide serait appréciée!

La sortie que j'ai ci-dessous est ce que je recherche, bien que dans mon exemple réel, j'ai utilisé des mots vides, donc les bigrammes exacts ne sont pas trouvés comme la sortie ci-dessous. Y a-t-il un moyen de faire avec une sorte de chaîne contient peut-être?

import pandas as pd 
data = [['help me with my python pandas please'], ['machine learning is fun using svd with sklearn']] 
# Create the pandas DataFrame 
df = pd.DataFrame(data, columns = ['Message']) 
import numpy as np
bigrams =[('python', 'pandas'),
 ('function', 'input'),
 ('help', 'jupyter'),
 ('sklearn', 'svd')]
def matcher(x):
    for i in bigrams:
        if i.lower() in x.lower():
            return i
    else:
        return np.nan

df['Match'] = df['Message'].apply(matcher)
df


6 commentaires

bien qu'il s'agisse d'un problème intéressant, vous devez toujours inclure des exemples de données et la sortie attendue pour ces données.


ok va faire, merci pour la suggestion.


Ceci est un exemple de code, je demandais cependant un exemple de données.


les seules données sur lesquelles je travaille pour cet objectif sont la liste bigramme et mon dataframe avec une phrase sur chaque ligne que je veux parcourir. Dans ce code, ce serait df ['documents']. Ex: chaque ligne contient un document avec une phrase comme «aidez-moi avec mon python» ou «l'apprentissage automatique est amusant». Cela a-t-il du sens?


Certes, même ces deux phrases fonctionneraient. Et vous devez spécifier ce que vous attendez de ces exemples de données.


Le code de cette question ne fonctionne pas pour moi, il donne: AttributeError: l'objet 'tuple' n'a pas d'attribut 'lower'.


3 Réponses :


3
votes

Voici ce que je ferais:

  function input  help jupyter  python pandas
0               0             0              1
1               1             1              0
2               0             0              0

vous donne

new_df.str.join(',').str.get_dummies(sep=',')

Ensuite, vous pouvez choisir de unnest la liste dans chaque ligne.

Ou vous pouvez utiliser get_dummies:

0                   [python pandas]
1    [function input, help jupyter]
2                                []
Name: sentences, dtype: object

ce qui vous donne:

# a sample, which you should've given
df = pd.DataFrame({'sentences': ['I like python pandas', 
                                 'find all function input from help jupyter',
                                 'this has no bigrams']})


# the bigrams
bigrams = [('python', 'pandas'),
 ('function', 'input'),
 ('help', 'jupyter'),
 ('sklearn', 'svd')]

# create one big regex pattern:
pat = '|'.join(" ".join(x) for x in bigrams)

new_df = df.sentences.str.findall(pat)


6 commentaires

à cause des mots vides que j'ai inclus, cela ne fonctionnera pas sur mes données d'origine. J'ai besoin de quelque chose qui recherche chaque bigramme individuellement. Plus comme un str.contains, mais pour chaque bigramme, puis me rend chaque bigramme qui est contenu.


Oui, cela pourrait ne pas fonctionner si vos bigrammes se chevauchent, comme (a, b) et (b, c) .


D'autres idées?


En fait, je peux créer une colonne en double, puis ajouter les mots vides à celle-ci, puis exécuter votre code sur cette colonne à la place peut-être! Je vais essayer.


Qu'est-ce que new_df?


@zabop La modification a en quelque sorte gâché mon message. Mis à jour, j'espère que c'est plus clair.



1
votes

Eh bien, voici ma solution avec la détection des termes bigrammes dans les énoncés (phrases) nettoyés.

Elle peut également être généralisée facilement aux n-grammes. Il prend également en compte les mots vides.

Vous pouvez régler:

  • target_depth (2 par défaut pour les bigrammes) si vous souhaitez rechercher un autre type de n-grammes.
  • le séparateur par défaut (espace) utilisé pour symboliser les mots d'une phrase.
  • votre ensemble de mots d'arrêt (en utilisant nltk ici pour les arrêts communs en anglais).

Veuillez noter que cette implémentation est récursive.

                               Match  
0                 [(python, pandas)]  
1                   [(svd, sklearn)]  
2  [(help, jupyter), (svd, sklearn)]

Nous obtenons en fait ces résultats:

import pandas as pd 
import re
from nltk.corpus import stopwords

data = [
    ['help me with my python pandas please'],
    ['machine learning is fun using svd with sklearn'],
    ['please use |svd| with sklearn, get help on JupyteR!']
]
# Create the pandas DataFrame 
df = pd.DataFrame(data, columns = ['Message']) 

bigrams =[
    ('python', 'pandas'),
    ('function', 'input'),
    ('help', 'jupyter'),
    ('svd', 'sklearn')
]

stop_words = set(stopwords.words('english'))
sep = ' '

def _cleanup_token(w):
    """ Cleanup a token by stripping special chars """
    return re.sub('[^A-Za-z0-9]+', '', w)

def _preprocessed_tokens(x):
    """ Preprocess a sentence. """
    return list(map(lambda w: _cleanup_token(w), x.lower().split(sep)))

def _match_bg_term_in_sentence(bg, x, depth, target_depth=2):
    """ """
    if depth == target_depth:
        return True # the whole bigram was matched

    term = bg[depth]
    term = term.lower()
    pp_tokens = _preprocessed_tokens(x)

    if term in pp_tokens:
        bg_idx = pp_tokens.index(term)
        if depth > 0 and any([token not in stop_words for token in pp_tokens[0:bg_idx]]):
            return False # no bigram detected
        x = sep.join(pp_tokens[bg_idx+1:])
        return _match_bg_term_in_sentence(bg, x, depth+1, target_depth=target_depth)
    else:
        return False

def matcher(x):
    """ Return list of bigrams matched in sentence x """
    depth = 0 # current depth
    matchs = []
    for bg in bigrams:
        bg_idx = 0 # first term
        bg_matchs = _match_bg_term_in_sentence(bg, x, depth, target_depth=2)
        if bg_matchs is True:
            matchs.append(bg)
    return matchs

df['Match'] = df['Message'].apply(matcher)
print(df.head())

J'espère que cela vous aidera!


0 commentaires

1
votes

flashtext peut également être utilisé pour résoudre ce problème

import pandas as pd
from flashtext import KeywordProcessor
from nltk.corpus import stopwords

stop = stopwords.words('english')
bigram_token = ['python pandas','function input', 'help jupyter','svd sklearn']

data = [['help me with my python pandas please'], ['machine learning is fun using svd 
with sklearn']] 

# Create the pandas DataFrame 
df = pd.DataFrame(data, columns = ['Message']) 

kp = KeywordProcessor()
kp.add_keywords_from_list(bigram_token)

def bigram_finder(x, stop, kp):
    token = x.split()
    sent = ' '.join([x for x in token if x not in stop])
    return kp.extract_keywords(sent)

df['bigram_token'] = df['Message'].apply(lambda x : bigram_finder(x, stop, kp))
#ouptput
 0    [python pandas]
 1      [svd sklearn]
 Name: bigram_token, dtype: object


0 commentaires