2017-09-04 34 views
3

我有一個數據幀(從CSV文件導出)用100M左右的條目,看起來像這樣:重新分配的條目爲多行了巨大的熊貓數據幀

df1: 

     var1  var2 
0   1  2 
1   2  1 
2   1 {3,4,5} 
3   5  6 
4 {4,5,6,7}  8 

我需要將其轉換成新數據幀,其中(每行)在括號每個元件需要與在另一列中的元件,即,相關聯的,

df2: 

    var1 var2 
0 1 2 
1 2 1 
2 1 3 
3 1 4 
4 1 5 
5 5 6 
6 4 8 
7 5 8 
8 6 8 
9 7 8 

每個元素是一個字符串,即使支架條目本身。請注意,支撐元素可以在任一列中。有誰知道我如何有效地實現這個約100M條目的數據集?提前致謝。

Python的例子:

import pandas as pd 

df1 = pd.DataFrame([{'var1': '1', 'var2': '2'}, 
       {'var1': '2', 'var2': '1'}, 
       {'var1': '1', 'var2': '{3,4,5}'}, 
       {'var1': '5', 'var2': '6'}, 
       {'var1': '{4,5,6,7}', 'var2': '8'}]) 


df2 = pd.DataFrame([{'var1': '1', 'var2': '2'}, 
       {'var1': '2', 'var2': '1'}, 
       {'var1': '1', 'var2': '3'}, 
       {'var1': '1', 'var2': '4'}, 
       {'var1': '1', 'var2': '5'}, 
       {'var1': '5', 'var2': '6'}, 
       {'var1': '4', 'var2': '8'}, 
       {'var1': '5', 'var2': '8'}, 
       {'var1': '6', 'var2': '8'}, 
       {'var1': '7', 'var2': '8'}]) 

我迄今所做的這一點,但它是緩慢的,以其他的數據幀。

# Put row with braces in the second column 
def swap_cols(row): 
    if '{' in row[0]: 
     return (row[1], row[0]) 
    return row 

# Convert the braces into a list 
def parse_str(s): 
    if '{' in s: 
     s = s[1:-1] 
     return s.split(',') 
    return [s] 


df3 = df1.apply(swap_cols, axis=1) 

df3.var2 = df3.var2.apply(parse_str) 

# Show that it works 
for ridx, row in df3.iterrows(): 
    for ele in row.var2: 
     print row.var1, ele 
+0

我加了numpy的標籤,這可能會吸引有趣的答案:) – IanS

+1

所以沒有答案是有幫助的嗎?我有興趣看看現實生活中的比較。 – IanS

回答

2

您可以使用np.vstacknp.meshgridreshape

sdf = df.apply(lambda x:(x.str.strip('{}').str.split(','))) 

def cartesian(x): 
    return np.vstack(np.array([np.array(np.meshgrid(*i)).T.reshape(-1,2) for i in x.values])) 

ndf = pd.DataFrame(cartesian(sdf),columns=sdf.columns) 

如果你想脫掉衣服,分裂,然後申請笛卡爾

%%time 
100 loops, best of 3: 4 ms per loop 

如果您有條紋和splited數據幀則:

1000 loops, best of 3: 564 µs per loop 

輸出:

 
    var1 var2 
0 1 2 
1 2 1 
2 1 3 
3 1 4 
4 1 5 
5 5 6 
6 4 8 
7 5 8 
8 6 8 
9 7 8 
0

你可以嘗試:

# isolate these cases as they will be treated separately 
case1 = df1['var1'].str.contains('{') 
case2 = df1['var2'].str.contains('}') 

# convert to lists 
import ast 
df1 = df1.apply(lambda col: col.str.replace('{', '[').str.replace('}', ']')) \ 
     .applymap(ast.literal_eval) 

在第二種情況:

df1[case2].groupby('var1')['var2'].apply(lambda g: pd.Series(g.sum())) \ 
      .reset_index(-1, drop=True).reset_index() 

應用sum會連接這些表(如果有一個以上)爲var1每個值,並且鑄造到pandas.Series將會呈現你正在尋找的形狀。

然後,您可以串聯一切恢復:

pd.concat([ 
    df1[~case1 & ~case2], 
    df1[case1].groupby('var2')['var1'].apply(lambda g: pd.Series(g.sum())).reset_index(-1, drop=True).reset_index(), 
    df1[case2].groupby('var1')['var2'].apply(lambda g: pd.Series(g.sum())).reset_index(-1, drop=True).reset_index() 
]).sort_values('var1') # sorting optional 
+0

應用pd.Series確實會降低性能。 – Dark

0

使用numpy.repeatnumpy.concatenate爲扁平化:

#create lists by remove {} and split 
splitted1 = df1['var1'].str.strip('{}').str.split(',') 
#get legths of lists 
lens1 = splitted1.str.len() 

splitted2 = pd.Series(np.repeat(df1['var2'].values, lens1)).str.strip('{}').str.split(',') 
lens2 = splitted2.str.len() 

df = pd.DataFrame({'a':np.repeat(np.concatenate(splitted1), lens2), 
        'b':np.concatenate(splitted2)}) 
print (df) 
    a b 
0 1 2 
1 2 1 
2 1 3 
3 1 4 
4 1 5 
5 5 6 
6 4 8 
7 5 8 
8 6 8 
9 7 8