2017-06-06 3 views
4

sagen, dass ich einen Datensatz haben, wieAnwenden von Spacy Parser zu Pandas Datenrahmen w/Multiprocessing

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

I Spacy und .apply verwenden, um eine String-Spalte in Token (meine wirklichen-Datensatz hat> 1 Wort/Token pro parsen Eintritt natürlich)

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

Ergebnis:

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

ich kann nutzen diese bequeme Multiprocessing-Funktion (thanks to this blogpost) auch willkürlichste gelten Funktionen auf einem Datenrahmen parallel zu tun:

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 

zum Beispiel:

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) 

Ergebnis:

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

... Aber aus irgendeinem Grund kann ich den Spacy-Parser nicht auf diese Weise auf einen Datenrahmen anwenden, der Multiprocessing verwendet.

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

iris = parallelize_dataframe(iris, add_parsed, num_cores) 

Ergebnis:

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

Gibt es eine andere Möglichkeit, dies zu tun? Ich liebe Spacy für NLP, aber ich habe eine Menge Textdaten und daher möchte ich einige Verarbeitungsfunktionen parallelisieren, bin aber auf dieses Problem gestoßen.

Antwort

7

Spacy ist stark optimiert und übernimmt die Mehrfachverarbeitung für Sie. Daher denke ich, dass es am besten ist, die Daten aus dem Dataframe herauszunehmen und sie als Liste an die Spacy-Pipeline zu übergeben, anstatt zu versuchen, .apply direkt zu verwenden.

Sie müssen dann die Ergebnisse der Analyse sammeln und diese wieder in den Dataframe einfügen.

Also, in Ihrem Beispiel, könnten Sie so etwas wie verwenden:

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 

Dieser Ansatz fein auf kleine Datenmengen arbeiten, aber es frisst Ihr Gedächtnis, also nicht großartig, wenn Sie große Mengen verarbeiten wollen von Text.

Verwandte Themen