2016-06-10 25 views
3

我在創建一個Dataframe,它是兩個無關係列的組合。從兩個不相關的系列創建DataFrame的最有效方法是什麼?

如果我們採取兩種dataframes:

A = ['a','b','c'] 
B = [1,2,3,4] 

dfA = pd.DataFrame(A) 
dfB = pd.DataFrame(B) 

我在尋找這樣的輸出:

A B 
0 a 1 
1 a 2 
2 a 3 
3 a 4 
4 b 1 
5 b 2 
6 b 3 
7 b 4 
8 c 1 
9 c 2 
10 c 3 
11 c 4 

的一種方式可能是對列表循環照片直接和創建數據框但必須有是更好的方法。我確信我錯過了熊貓文檔中的一些東西。

result = [] 
for i in A: 
    for j in B: 
     result.append([i,j]) 

result_DF = pd.DataFrame(result,columns=['A','B']) 

最終我看着合併個月UUID,我有一些工作,但它需要年齡計算,並依賴過多的索引。一個通用的解決方案顯然更好:

from datetime import datetime 

start = datetime(year=2016,month=1,day=1) 
end = datetime(year=2016,month=4,day=1) 
months = pd.DatetimeIndex(start=start,end=end,freq="MS") 
benefit = pd.DataFrame(index=months) 

A = [UUID('d48259a6-80b5-43ca-906c-8405ab40f9a8'), 
    UUID('873a65d7-582c-470e-88b6-0d02df078c04'), 
    UUID('624c32a6-9998-49f4-92b6-70e712355073'), 
    UUID('7207ab0c-3c7f-477e-b5bc-fbb8059c1dec')] 
dfA = pd.DataFrame(A) 

result = pd.DataFrame(columns=['A','month']) 
for i in dfA.index: 
    newdf = pd.DataFrame(index=benefit.index) 
    newdf['A'] = dfA.iloc[i,0] 
    newdf['month'] = newdf.index 
    result = pd.concat([result,newdf]) 
result 

回答

3

您可以使用np.meshgrid

pd.DataFrame(np.array(np.meshgrid(dfA, dfB,)).T.reshape(-1, 2)) 

    0 1 
0 a 1 
1 a 2 
2 a 3 
3 a 4 
4 b 1 
5 b 2 
6 b 3 
7 b 4 
8 c 1 
9 c 2 
10 c 3 
11 c 4 

獲得分別長300DataFrame對象和400,大致~2000x加速:

A = ['a', 'b', 'c'] * 100 
B = [1, 2, 3, 4] * 100 

dfA = pd.DataFrame(A) 
dfB = pd.DataFrame(B) 

np.meshgrid

%%timeit 
pd.DataFrame(np.array(np.meshgrid(dfA, dfB,)).T.reshape(-1, 2)) 
100 loops, best of 3: 8.45 ms per loop 

VS cross

%timeit cross(dfA, dfB) 
1 loop, best of 3: 16.3 s per loop 

所以,如果我理解正確你的榜樣,你可以:

A = ['a', 'b', 'c'] 
dfA = pd.DataFrame(A) 

start = datetime(year=2016, month=1, day=1) 
end = datetime(year=2016, month=4, day=1) 
months = pd.DatetimeIndex(start=start, end=end, freq="MS") 
dfB = pd.DataFrame(months.month) 

pd.DataFrame(np.array(np.meshgrid(dfA, dfB,)).T.reshape(-1, 2)) 

也得到:

0 1 
0 a 1 
1 a 2 
2 a 3 
3 a 4 
4 b 1 
5 b 2 
6 b 3 
7 b 4 
8 c 1 
9 c 2 
10 c 3 
11 c 4 
+0

似乎非常快,但僅適用於適合np數組的數據類型。如果我嘗試使用UUID,我會得到'TypeError:不受支持的操作數類型' – ludofet

+0

你在看什麼'dtype'? – Stefan

+0

查看已更新的答案,如果我誤解了您的示例,請告訴我。 – Stefan

0

一個襯墊的方法

pd.DataFrame(0, A, B).stack().index.to_series().apply(pd.Series).reset_index(drop=True) 

或者:

pd.MultiIndex.from_product([A, B]).to_series().apply(pd.Series).reset_index(drop=True) 

從dataframes,假設信息是第一列。

pd.MultiIndex.from_product([dfA.iloc[:, 0], dfB.iloc[:, 0]]).to_series().apply(pd.Series).reset_index(drop=True) 

功能化:

def cross(df1, df2): 
    s1 = df1.iloc[:, 0] 
    s2 = df2.iloc[:, 0] 
    midx = pd.MultiIndex.from_product([s1, s2]) 
    df = midx.to_series().apply(pd.Series).reset_index(drop=True) 
    df.columns = [s1.name, s2.name if s1.name != s2.name else 1] 
    return df 

print cross(dfA, dfB) 

    0 1 
0 a 1 
1 a 2 
2 a 3 
3 a 4 
4 b 1 
5 b 2 
6 b 3 
7 b 4 
8 c 1 
9 c 2 
10 c 3 
11 c 4 
+0

這是一個很好的單線程,我將存儲,但它仍然需要列表而不是DataFrame作爲輸入,對嗎? – ludofet

+0

編輯爲帳戶使用'dfA'和'dfB' – piRSquared

+0

謝謝!在我的簡單示例中看看事物的性能方面,它看起來像組合數據框比使用循環和列表慢10倍。我想這是一個很小的問題。 – ludofet

2

或者

a = [1,2,3] 
b = ['a','b','c'] 
x,y = zip(*[i for i in zip(np.tile(a,len(a)),np.tile(b,len(a)))]) 
pd.DataFrame({'x':x,'y':y}) 

輸出:

x y 
0 1 a 
1 2 b 
2 3 c 
3 1 a 
4 2 b 
5 3 c 
6 1 a 
7 2 b 
8 3 c 

%%timeit 
1000 loops, best of 3: 559 µs per loop 

編輯:你實際上並不需要np.tile。一個簡單的理解會做

x,y = zip(*[(i,j) for i in a for j in b]) 
2

使用itertools.product

from itertools import product 

result = pd.DataFrame(list(product(dfA.iloc[:,0], dfB.iloc[:,0]))) 

不太一樣有效,np.meshgrid,但它比其他解決方案更有效。

相關問題