2017-10-24 3 views
2

Wie die meisten Pandas Probleme, ich denke, das Problem wurde bereits behandelt, aber ich kann keine direkte Antwort finden und ich mache mir auch Sorgen über die Leistung. Mein Dataset ist groß, also hoffe ich, die effizienteste Art zu finden.DataFrame transponieren von Liste

Das Problem Ich habe 2 Datenrahmen - dfA enthält eine Liste von IDs von dfB. Ich mag würde

zu
  1. transponieren diese IDs als Spalten
  2. die IDs ersetzen mit einem Wert von dfb
  3. Zusammenbruch wiederholt Spalten nachgeschlagen und Aggregat mit Summe

Hier ist eine Illustration:

dfA

dfA = pd.DataFrame({'a_id':['0000001','0000002','0000003','0000004'], 
        'list_of_b_id':[['2','3','7'],[],['1','2','3','4'],['6','7']] 
        }) 

+------+--------------+ 
| a_id | list_of_b_id | 
+------+--------------+ 
| 1 | [2, 3, 7] | 
+------+--------------+ 
| 2 | []   | 
+------+--------------+ 
| 3 | [1, 2, 3, 4] | 
+------+--------------+ 
| 4 | [6, 7]  | 
+------+--------------+ 

dfb

dfB = pd.DataFrame({'b_id':['1','2','3','4','5','6','7'], 
        'replacement': ['Red','Red','Blue','Red','Green','Blue','Red'] 
        }) 

+------+-------------+ 
| b_id | replacement | 
+------+-------------+ 
| 1 | Red   | 
+------+-------------+ 
| 2 | Red   | 
+------+-------------+ 
| 3 | Blue  | 
+------+-------------+ 
| 4 | Red   | 
+------+-------------+ 
| 5 | Orange  | 
+------+-------------+ 
| 6 | Blue  | 
+------+-------------+ 
| 7 | Red   | 
+------+-------------+ 

Tor (Endergebnis) Hier ist, was ich bin der Hoffnung, auf, um schließlich zu bekommen, auf die effizienteste Art und Weise möglich.

In Wirklichkeit kann ich über 5M Obs sowohl in dfA und dfB, und ~ 50 eindeutige Werte für den Ersatz in dfB haben, was erklärt, warum ich dies auf dynamische Weise tun muss und nicht nur hart-Code.

+------+-----+------+ 
| a_id | Red | Blue | 
+------+-----+------+ 
| 1 | 2 | 1 | 
+------+-----+------+ 
| 2 | 0 | 0 | 
+------+-----+------+ 
| 3 | 3 | 1 | 
+------+-----+------+ 
| 4 | 1 | 1 | 
+------+-----+------+ 

Antwort

1

Zuerst werden alle Listen werden Abflachen von numpy.repeat und numpy.concatenate:

df = pd.DataFrame({'id':np.repeat(dfA['a_id'], dfA['list_of_b_id'].str.len()), 
        'b': np.concatenate(dfA['list_of_b_id'])}) 

print (df) 
    b  id 
0 2 0000001 
0 3 0000001 
0 7 0000001 
2 1 0000003 
2 2 0000003 
2 3 0000003 
2 4 0000003 
3 6 0000004 
3 7 0000004 

Dann map von Series von dfB erstellt, die für groupby für Zählungen verwendet wird, neu zu gestalten, indem unstack und fehlende Werte hinzufügen, indem reindex :

df = (df.groupby(['id',df['b'].map(dfB.set_index('b_id')['replacement'])]) 
     .size() 
     .unstack(fill_value=0) 
     .reindex(dfA['a_id'].unique(), fill_value=0)) 
print (df) 
b  Blue Red 
id     
0000001  1 2 
0000002  0 0 
0000003  1 3 
0000004  1 1 

print (df['b'].map(dfB.set_index('b_id')['replacement'])) 
0  Red 
0 Blue 
0  Red 
2  Red 
2  Red 
2 Blue 
2  Red 
3 Blue 
3  Red 
Name: b, dtype: object 
+0

Bei einer Stichprobe von 50K-Datensätzen in dfA- und 5M-Datensätzen in dfB dauerte dies 0,67 Minuten! – Josh

+0

Es ist eine gute Zeit, danke für die Annahme! – jezrael

0
a = [['2','3','7'],[],['1','2','3','4'],['6','7']] 
    b =['Red','Red','Blue','Red','Green','Blue','Red'] 
    res = [] 
    for line in a: 
    tmp = {} 
    for ele in line: 
     tmp[b[int(ele)-1]] = tmp.get(b[int(ele)-1], 0) +1 
    res.append(tmp) 

    print pd.DataFrame(res).fillna(0) 

    Blue Red 
0 1.0 2.0 
1 0.0 0.0 
2 1.0 3.0 
3 1.0 1.0 
0

Verwenden

In [5611]: dft = (dfA.set_index('a_id')['list_of_b_id'] 
        .apply(pd.Series) 
        .stack() 
        .replace(dfB.set_index('b_id')['replacement']) 
        .reset_index()) 

In [5612]: (dft.groupby(['a_id', 0]).size().unstack() 
       .reindex(dfA['a_id'].unique(), fill_value=0)) 
Out[5612]: 
0  Blue Red 
a_id 
0000001  1 2 
0000002  0 0 
0000003  1 3 
0000004  1 1 

Einzelheiten

In [5613]: dft 
Out[5613]: 
     a_id level_1  0 
0 0000001  0 Red 
1 0000001  1 Blue 
2 0000001  2 Red 
3 0000003  0 Red 
4 0000003  1 Red 
5 0000003  2 Blue 
6 0000003  3 Red 
7 0000004  0 Blue 
8 0000004  1 Red 
0

Sie können den Code unten versuchen:

pd.concat([dfA, dfA.list_of_b_id.apply(lambda x: dfB[dfB.b_id.isin(x)].replacement.value_counts())], axis=1) 
0
d=dfB.set_index('b_id').T.to_dict('r')[0] 

dfA['list_of_b_id']=dfA['list_of_b_id'].apply(lambda x : [d.get(k,k) for k in x]) 
pd.concat([dfA,pd.get_dummies(dfA['list_of_b_id'].apply(pd.Series).stack()).sum(level=0)],axis=1) 


Out[66]: 
     a_id   list_of_b_id Blue Red 
0 0000001  [Red, Blue, Red] 1.0 2.0 
1 0000002      [] NaN NaN 
2 0000003 [Red, Red, Blue, Red] 1.0 3.0 
3 0000004   [Blue, Red] 1.0 1.0 
Verwandte Themen