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
3 Réponses :
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)
à 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.
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:
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!
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
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'.