2016-08-29 3 views
2

Ich habe, was ich hoffe, ein einzigartiges/interessantes Problem für meine erste Frage zu Stack Overflow!Hunderter von Spalten und Spaltenindizes zu einer Zeichenkette zusammenfügen

Ich habe Daten über Fähigkeiten Bewertungen, derzeit in einem sehr großen Pandas Datenrahmen. Jede Zeile repräsentiert einen Schüler und jede Spalte enthält ihre Punkte für eine bestimmte Fähigkeitsbewertung. Insgesamt gibt es etwa 200 Skills Assessments, wobei jeder Student nur eine kleine Teilmenge dieser Assessments bewertet (1 - 20 Scores sind typisch, aber einige Studenten haben mehr).

Beispiel Datenrahmen Struktur:

id skill1 skill2 skill3 skill4 skill5 .... 
1  10  50  NaN  3  NaN 
2  Nan  10  2  70  NaN 
3  23  NaN  45  NaN  5 

ich versucht bin, diese Daten in eine durch Leerzeichen getrennte Zeichenfolge für jeden Schüler umgewandelt zu bekommen, in folgendem Format, so dass wir sie in einen anderen Datenspeicher importieren:

skill1:10 skill2:50 skill4:3 
skill2:10 skill3:2 skill4:70 

(beachten Sie, wie Fähigkeiten ohne Einschätzungen Partituren in die Liste nicht hinzugefügt bekommen)

ich habe eine Lambda-Funktion verbinden alle die geschaffen se Fähigkeit Werte mit ihren Spaltenbeschriftungen:

skillmerge = lambda row: ' '.join([str(row.index[i])+':'+str(row[i]) for i in range(0,len(row)) if row[i]!=np.nan]) 

Wenn ich eine einzige Serie erstellt (1 Teilnehmer) zu testen, auf der Lambda-Funktion dauert weniger als eine Sekunde, um die Ausgabezeichenfolge in meinem gewünschten Format zu erstellen. Allerdings, wenn ich einen Datenrahmen mit nur 2 Reihen (wieder für Testzwecke) zu erstellen, die Funktion nur einige Minuten in Anspruch nimmt, diese zwei Zeilen zu vervollständigen:

testing_df['combined_skills'] = testing_df.apply(skillmerge, axis=1) 

Da, wie ich habe ein paar Millionen Studenten in diesem Datensatz, Ich suche nach einem Weg, um diesen Prozess zuverlässig schneller arbeiten zu lassen. Irgendwelche Gedanken, wo ich das beheben kann?

Vielen Dank im Voraus für die Hilfe bei meiner ersten SO Frage! : D

+0

Sie konnten die 'row.index nur berechnen [i]', bevor die Liste Verständnis, da die Etiketten gleich bleiben –

+0

Nun, sie nicht genau konstant bleiben. Das gewünschte Ausgabeformat enthält keine Fähigkeiten, für die kein Bewertungsfaktor vorhanden ist. –

+0

Nein, aber Ihr Listenverständnis wird immer noch jeden Wert von "i" in "Bereich (len (Indizes))" gegen "row [i]! = Np.nan" testen. Sie könnten also vorher eine Liste mit allen Indizes erstellen, z. 'my_index_list = [skill1, skill2, ... skilln]' und ändere dann 'row.index [i]' in 'my_index_list [i]'. Es ist mir nicht klar, warum Runtime mit nur 1 zusätzlichen Zeile explodieren würde. – roganjosh

Antwort

1

to_json dann verwenden sie zur Festsetzung

def to_str(x): 
    return x.dropna().to_json(double_precision=0) \ 
      .replace('"', '').replace(',', ' ').strip("{}") 

df.T.apply(to_str) 

Oder mit Liste Verständnis und join

def to_str(x): 
    return " ".join(["{}:{}".format(k, int(v)) for k, v in x.dropna().iteritems()]) 

df.T.apply(to_str) 

Beide

id 
1 skill1:10 skill2:50 skill4:3 
2 skill2:10 skill3:2 skill4:70 
3 skill1:23 skill3:45 skill5:5 
dtype: object 

geben machen Ihre Lösung Arbeit

skillmerge = lambda row: ' '.join([str(row.index[i])+':'+str(row[i]) for i in range(len(row)) if not np.isnan(row[i])]) 

df.T.apply(skillmerge) 

Beachten Sie, dass np.nan == np.nan-False auswertet. Um für np.nan zu testen, verwenden Sie np.isnan oder pd.isnull oder pd.notnull. Diese Tatsache hat Ihre Lösung abgeworfen. Ich habe es durch not np.isnan ersetzt und es funktioniert.

Ich nahm die Gelegenheit zu tun, was ich tun würde, weil ich es besser mag.

+0

... Das ist großartig, upvote. Können Sie irgendeinen Einblick geben, warum der ursprüngliche Ansatz verrückt wurde, da dieser grundsätzlich anders ist? Warum 'to_json'? – roganjosh

+1

@roganjosh Ich habe gerade meinen Beitrag mit einer Erklärung aktualisiert, warum die OP-Lösung nicht funktionierte. – piRSquared

+0

@piRSquared Danke! Als Sidnote zeigt mein Systemmonitor, dass Ihr Ansatz auch viel speichereffizienter ist. –

0

Try this:

ld = df.set_index('id').fillna("").to_dict(orient='records') 
ll = [' '.join([ k +":"+ str(v) for k,v in x.iteritems() if v != "" ]) for x in ld ] 
ll 

['skill2:50.0 skill1:10.0 skill4:3.0', 
'skill3:2.0 skill2:10.0 skill4:70.0', 
'skill3:45.0 skill1:23.0 skill5:5.0'] 
Verwandte Themen