Ich arbeite an der Textanalyse und versuche, den Wert des Satzes als die Summe des Wertes zu quantifizieren, der einigen Wörtern zugewiesen wurde, wenn sie im Satz enthalten sind. Ich habe einen DF mit Wörtern und Werten wie:
import pandas as pd
df_w = pd.DataFrame( { 'word': [ 'high', 'sell', 'hello'],
'value': [ 32, 45, 12] } )
Dann habe ich Sätze in einem anderen DF wie:
df_s = pd.DataFrame({'sentence': [ 'hello life if good',
'i sell this at a high price',
'i sell or you sell'] } )
Jetzt möchte ich eine Spalte in df_s
mit der Summe des Werts jedes Wortes im Satz hinzufügen, wenn sich das Wort in df_w
befindet. Dazu habe ich versucht:
df_s['value'] = df_s['sentence'].apply(lambda x: sum(df_w['value'][df_w['word'].isin(x.split(' '))]))
Das Ergebnis ist:
sentence value
0 hello life if good 12
1 i sell this at a high price 77
2 i sell or you sell 45
Mein Problem mit dieser Antwort ist, dass ich für den letzten Satz i sell or you sell
zweimal sell
habe und 90 (2 * 45) erwartet habe, aber sell
nur einmal berücksichtigt wurde, sodass ich 45 bekam .
Um dies zu lösen, habe ich beschlossen, ein Wörterbuch zu erstellen und dann ein apply
zu erstellen:
dict_w = pd.Series(df_w['value'].values,index=df_w['word']).to_dict()
df_s['value'] = df_s['sentence'].apply(lambda x: sum([dict_w[word] for word in x.split(' ') if word in dict_w.keys()]))
Dieses Mal ist das Ergebnis das, was ich erwartet habe (90 für den letzten Satz). Mein Problem tritt jedoch bei größeren DF auf, und die Zeit zum Ausführen der Methode mit dict_w
ist ungefähr 20 Mal länger als die Methode mit isin
für meinen Testfall.
Kennen Sie eine Möglichkeit, den Wert eines Wortes mit seinem Auftreten in der Methode mit isin
zu multiplizieren? Jede andere Lösung ist ebenfalls willkommen.
3 Antworten
Dank der Antwort von piRSquared mit seiner map
-Funktion hatte ich die Idee, Merge zu verwenden, wie zum Beispiel:
df_s['value'] = df_s['sentence'].apply(lambda x: sum(pd.merge(pd.DataFrame({'word':x.split(' ')}),df_w)['value']))
Dank der Antwort von Wen mit seiner stack
-Funktion verwende ich seine Idee, aber mit merge
wie:
df_stack = pd.DataFrame({'word': df_s['sentence'].str.split(' ',expand=True).stack()})
df_s['value'] = df_stack.reset_index().merge(df_w).set_index(['level_0','level_1'])['value'].sum(level=0)
Und beide Methoden geben mir die richtige Antwort. Um zu testen, welche Lösung schneller ist, definiere ich Funktionen wie:
def sol_dict (df_s, df_w): # answer with a dict
dict_w = pd.Series(df_w['value'].values,index=df_w['word']).to_dict()
df_s['value'] = df_s['sentence'].apply(lambda x: sum([dict_w[word] for word in x.split(' ') if word in dict_w.keys()]))
return df_s
def sol_wen(df_s, df_w): # answer of Wen
s=df_s.sentence.str.split(' ',expand=True).stack()
df_s['value']=s[s.isin(df_w.word)].replace(dict(zip(df_w.word,df_w.value))).sum(level=0)
return df_s
def sol_pi (df_s, df_w): # answer of piRSquared
dw = lambda x: dict(zip(df_w.word, df_w.value)).get(x, 0)
df_s.assign(value=[sum(map(dw, s.split())) for s in df_s.sentence])
# or df_s['value'] = [sum(map(dw, s.split())) for s in df_s.sentence]
return df_s
def sol_merge(df_s, df_w): # answer with merge
df_s['value'] = df_s['sentence'].apply(lambda x: sum(pd.merge(pd.DataFrame({'word':x.split(' ')}),df_w)['value']))
return df_s
def sol_stack(df_s, df_w): # answer with stack and merge
df_stack = pd.DataFrame({'word': df_s['sentence'].str.split(' ',expand=True).stack()})
df_s['value'] = df_stack.reset_index().merge(df_w).set_index(['level_0','level_1'])['value'].sum(level=0)
return df_s
Meine "großen" Test-DFs bestanden aus ungefähr 3200 Wörtern in df_w und ungefähr 42700 Wörtern in df_s (einmal alle Sätze aufgeteilt). Ich führe timeit
mit mehreren Größen von df_w (von 320 bis 3200 Wörtern) mit der vollen Größe von df_s und dann mit mehreren Größen von df_s (von 3500 bis 42700 Wörtern) mit der vollen Größe von df_w aus. Nachdem ich meine Ergebnisse an die Kurve angepasst hatte, erhielt ich:
Unabhängig von der Größe beider DFs ist die Methode mit stack
und dann merge
sehr effizient (ca. 100 ms, in Diagrammen leider nicht wirklich sichtbar). Ich führe es auf meinen DFs in voller Größe mit ungefähr 54.000 Wörtern in df_w
und 2,4 Millionen Wörtern in df_s
aus und erhalte die Ergebnisse in wenigen Sekunden. Vielen Dank für Ihre Ideen.
Sie können str.split
mit stack
verwenden und das Ergebnis filtern (isin
), replace
diese Schlüsselwörter bewerten und dann zurückweisen
s=df_s.sentence.str.split(' ',expand=True).stack()
df_s['Value']=s[s.isin(df_w.word)].replace(dict(zip(df_w.word,df_w.value))).sum(level=0)
df_s
Out[984]:
sentence Value
0 hello life if good 12
1 i sell this at a high price 77
2 i sell or you sell 90
Erstellen Sie eine Funktion mit einem Standardwert aus der get
-Methode eines Wörterbuchs
dw = lambda x: dict(zip(df_w.word, df_w.value)).get(x, 0)
df_s.assign(value=[sum(map(dw, s.split())) for s in df_s.sentence])
sentence value
0 hello life if good 12
1 i sell this at a high price 77
2 i sell or you sell 90
Verwandte Fragen
Neue Fragen
python
Python ist eine dynamisch typisierte Mehrzweck-Programmiersprache mit mehreren Paradigmen. Es wurde entwickelt, um schnell zu lernen, zu verstehen, zu verwenden und eine saubere und einheitliche Syntax durchzusetzen. Bitte beachten Sie, dass Python 2 ab dem 01.01.2020 offiziell nicht mehr unterstützt wird. Fügen Sie für versionenspezifische Python-Fragen das Tag [python-2.7] oder [python-3.x] hinzu. Wenn Sie eine Python-Variante (z. B. Jython, PyPy) oder eine Bibliothek (z. B. Pandas und NumPy) verwenden, fügen Sie diese bitte in die Tags ein.