2016-06-10 28 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,但它比其他解决方案更有效。

相关问题