Ich habe Datenrahmen mit jeder Zeile mit einem Listenwert.
id list_of_value
0 ['a','b','c']
1 ['d','b','c']
2 ['a','b','c']
3 ['a','b','c']
Ich muss eine Punktzahl mit einer Zeile und gegen alle anderen Zeilen berechnen
Zum Beispiel:
Step 1: Take value of id 0: ['a','b','c'],
Step 2: find the intersection between id 0 and id 1 ,
resultant = ['b','c']
Step 3: Score Calculation => resultant.size / id.size
Wiederholen Sie Schritt 2,3 zwischen ID 0 und ID 1,2,3, ähnlich für alle IDs.
und einen N x N Datenrahmen erstellen; wie das:
- 0 1 2 3
0 1 0.6 1 1
1 1 1 1 1
2 1 1 1 1
3 1 1 1 1
Im Moment hat mein Code nur eine for-Schleife:
def scoreCalc(x,queryTData):
#mathematical calculation
commonTData = np.intersect1d(np.array(x),queryTData)
return commonTData.size/queryTData.size
ids = list(df['feed_id'])
dfSim = pd.DataFrame()
for indexQFID in range(len(ids)):
queryTData = np.array(df.loc[df['id'] == ids[indexQFID]]['list_of_value'].values.tolist())
dfSim[segmentDfFeedIds[indexQFID]] = segmentDf['list_of_value'].apply(scoreCalc,args=(queryTData,))
Gibt es einen besseren Weg, dies zu tun? Kann ich einfach eine Apply-Funktion schreiben, anstatt eine For-Loop-Iteration durchzuführen? kann ich es schneller machen?
list_of_value
?list_of_value
. Ich meine insgesamt über alle Zeilen hinweg.Antworten:
Wenn Ihre Daten nicht zu groß sind, können Sie
get_dummies
die Werte codieren und eine Matrixmultiplikation durchführen:Ausgabe:
Update : Hier ist eine kurze Erklärung für den Code. Die Hauptidee besteht darin, die angegebenen Listen in eine Hot-Codierung umzuwandeln:
Sobald wir das haben, sagen , dass die Größe des Schnittpunktes der beiden Reihen,
0
und1
nur ihr Punktprodukt, weil ein Zeichen für beiden Reihen gehört , wenn und nur wenn sie durch vertreten ist1
in beide.In diesem Sinne zuerst verwenden
um jede Zelle in eine Reihe zu verwandeln und alle diese Reihen zu verketten. Ausgabe:
Jetzt verwenden wir
pd.get_dummies
diese Serie, um sie in einen One-Hot-codierten Datenrahmen umzuwandeln:Wie Sie sehen können, hat jeder Wert eine eigene Zeile. Da wir diese, die zu derselben ursprünglichen Zeile gehören, zu einer Zeile kombinieren möchten, können wir sie einfach durch den ursprünglichen Index summieren. Somit
gibt den gewünschten binär codierten Datenrahmen an. Die nächste Zeile
ist genau wie Ihre Logik:
s.dot(s.T)
Berechnet Punktprodukte durch Zeilen und.div(s.sum(1))
teilt dann die Anzahl durch Zeilen.quelle
12k x 12k
Datenrahmen enden. Sollte in Ordnung sein, wenn Sie ungefähr ein paar hundert eindeutige Werte haben.Versuche dies
Ausgabe
Sie können dies auch wie folgt tun
quelle
Verwenden Sie das Verständnis verschachtelter Listen in der Liste der Mengen
s_list
. Verwenden Sie im Rahmen des Listenverständnisses dieintersection
Operation, um Überlappungen zu überprüfen und die Länge jedes Ergebnisses zu ermitteln. Erstellen Sie abschließend den Datenrahmen und teilen Sie ihn durch die Länge jeder Liste indf.list_of_value
Falls jede Liste doppelte Werte enthält, sollten Sie
collections.Counter
anstelle von verwendenset
. Ich habe die Beispieldaten id = 0 in['a','a','c']
und id = 1 in geändert['d','b','a']
quelle
Aktualisiert
Da viele Kandidatenlösungen vorgeschlagen werden, scheint es eine gute Idee zu sein, eine Timing-Analyse durchzuführen. Ich habe einige zufällige Daten mit 12.000 Zeilen generiert, wie vom OP angefordert, wobei die 3 Elemente pro Satz beibehalten wurden, aber die Größe des verfügbaren Alphabets zum Auffüllen der Sätze erweitert wurde. Dies kann an die tatsächlichen Daten angepasst werden.
Lassen Sie mich wissen, ob Sie eine Lösung haben, die Sie testen oder aktualisieren möchten.
Installieren
Aktueller Gewinner
Anwärter
Originalbeitrag mit Lösungsdetails
Es ist möglich, dies
pandas
mit einem Self-Join zu tun .Wie andere Antworten gezeigt haben, besteht der erste Schritt darin, die Daten in eine längere Form zu entpacken.
Aus dieser Tabelle ist es möglich, die Anzahl pro ID zu berechnen.
Und dann kommt die Selbstverbindung, die in der
value
Spalte stattfindet. Dadurch werden IDs für jeden Schnittwert einmal gepaart, sodass die gepaarten IDs gezählt werden können, um die Schnittgrößen zu erhalten.Diese beiden können dann zusammengeführt und eine Punktzahl berechnet werden.
Wenn Sie die Matrixform bevorzugen, ist dies mit a möglich
pivot
. Dies ist eine viel größere Darstellung, wenn die Daten spärlich sind.quelle
Diese Lösung wird effizient mit jeder Größe von Daten arbeiten , und jede Art von Werten in Ihrem
list
sagt seinstr
oderint
oder auf andere Weise, auch den repetitiven Wertes , wenn eine zu kümmern.In diesem Fall ist das Listenverständnis besser, da das Append-Attribut der Liste nicht geladen und bei jeder Iteration als Funktion aufgerufen werden muss. Mit anderen Worten und im Allgemeinen ist das Listenverständnis schneller, da das Anhalten und Fortsetzen des Funktionsrahmens oder in anderen Fällen mehrere Funktionen langsamer sind als das Erstellen einer Liste bei Bedarf.
Die Verwendung eines Listenverständnisses anstelle einer Schleife, die keine Liste erstellt, eine Liste sinnloser Werte unsinnig akkumuliert und die Liste dann wegwirft, ist häufig langsamer, da das Erstellen und Erweitern der Liste aufwändig ist.
Ergebnis:
Ausführungszeit:
quelle
Sie können die Liste in eine Menge konvertieren und mithilfe der Schnittfunktion nach Überlappungen suchen:
(Nur 1 Apply-Funktion wird verwendet, wie Sie gefragt haben :-))
quelle
Ich würde verwenden
product
, um alle Kombinationen zu bekommen. Dann können wir überprüfen mitnumpy.isin
undnumpy.mean
:Zeitprobe
quelle
Sollte schnell sein, berücksichtigen Sie auch das Duplikat in der Liste
quelle
Ja! Wir suchen hier nach einem kartesischen Produkt, das in dieser Antwort angegeben ist. Dies kann ohne eine for-Schleife oder ein Listenverständnis erreicht werden
Fügen wir unserem Datenrahmen einen neuen wiederholten Wert hinzu,
df
damit er so aussieht:Weiter mit sich selbst verschmelzen
So sieht der zusammengeführte Frame aus:
Dann wenden wir mit jeder Zeile die gewünschte Funktion an
axis=1
Umformen, um Werte im gewünschten Format zu erhalten
Hoffe das hilft :)
quelle