2017-06-06 4 views
4

Dire que j'ai un jeu de données, commeApplication Spacy Parser à Pandas dataframe w/multitraitement

iris = pd.DataFrame(sns.load_dataset('iris')) 

Je peux utiliser Spacy et .apply pour analyser une colonne de chaîne en jetons (mon vrai jeu de données a> 1 mot/jeton par entrée bien sûr)

import spacy # (I have version 1.8.2) 
nlp = spacy.load('en') 
iris['species_parsed'] = iris['species'].apply(nlp) 

résultat:

sepal_length ... species species_parsed 
0   1.4 ... setosa   (setosa) 
1   1.4 ... setosa   (setosa) 
2   1.3 ... setosa   (setosa) 

je peux également utiliser cette fonction multitraitement pratique (thanks to this blogpost) pour appliquer le faire le plus arbitraire des fonctions sur une trame de données en parallèle:

from multiprocessing import Pool, cpu_count 
def parallelize_dataframe(df, func, num_partitions): 

    df_split = np.array_split(df, num_partitions) 
    pool = Pool(num_partitions) 
    df = pd.concat(pool.map(func, df_split)) 

    pool.close() 
    pool.join() 
    return df 

par exemple:

def my_func(df): 
    df['length_of_word'] = df['species'].apply(lambda x: len(x)) 
    return df 

num_cores = cpu_count() 
iris = parallelize_dataframe(iris, my_func, num_cores) 

Résultat:

sepal_length species length_of_word 
0   5.1 setosa    6 
1   4.9 setosa    6 
2   4.7 setosa    6 

... Mais pour une raison quelconque, je ne peux pas appliquer l'analyseur Spacy à une base de données en utilisant le multitraitement de cette façon.

def add_parsed(df): 
    df['species_parsed'] = df['species'].apply(nlp) 
    return df 

iris = parallelize_dataframe(iris, add_parsed, num_cores) 

Résultat:

sepal_length species length_of_word species_parsed 
0   5.1 setosa    6   () 
1   4.9 setosa    6   () 
2   4.7 setosa    6   () 

Y at-il une autre façon de le faire? J'adore Spacy pour NLP mais j'ai beaucoup de données de texte et donc je voudrais paralléliser certaines fonctions de traitement, mais a rencontré ce problème.

Répondre

7

Spacy est hautement optimisé et fait le multitraitement pour vous. En conséquence, je pense que votre meilleur pari est de retirer les données de la base de données et de les transmettre au pipeline Spacy sous forme de liste plutôt que d'essayer d'utiliser .apply directement.

Vous devez ensuite rassembler les résultats de l'analyse et les replacer dans la structure de données.

Ainsi, dans votre exemple, vous pouvez utiliser quelque chose comme:

tokens = [] 
lemma = [] 
pos = [] 

for doc in nlp.pipe(df['species'].astype('unicode').values, batch_size=50, 
         n_threads=3): 
    if doc.is_parsed: 
     tokens.append([n.text for n in doc]) 
     lemma.append([n.lemma_ for n in doc]) 
     pos.append([n.pos_ for n in doc]) 
    else: 
     # We want to make sure that the lists of parsed results have the 
     # same number of entries of the original Dataframe, so add some blanks in case the parse fails 
     tokens.append(None) 
     lemma.append(None) 
     pos.append(None) 

df['species_tokens'] = tokens 
df['species_lemma'] = lemma 
df['species_pos'] = pos 

Cette approche fonctionne très bien sur les petits ensembles de données, mais il mange votre mémoire, donc pas grand si vous voulez traiter d'énormes quantités de texte.