这是一个自我回答的问题。给定两个dataFrame,
x
0 1
0 1 2
1 3 4
y
0 1 2
0 5 6 7
1 8 9 X
2 Y Z 0
x和y的对角连接由下式给出:
0 1 3 4 5
0 1.0 2.0 NaN NaN NaN
1 3.0 4.0 NaN NaN NaN
2 NaN NaN 5 6 7
3 NaN NaN 8 9 X
4 NaN NaN Y Z 0
最简单最简单的方法是什么?我想考虑两种情况:
答案 0 :(得分:4)
首先,简单的情况。假设标题和索引都是单调数字的,您只需将y
的索引器修改为x
的偏移量:
y.index += x.index[-1] + 1
y.columns += x.columns[-1] + 1
pd.concat([x, y])
0 1 2 3 4
0 1.0 2.0 NaN NaN NaN
1 3.0 4.0 NaN NaN NaN
2 NaN NaN 5 6 7
3 NaN NaN 8 9 X
4 NaN NaN Y Z 0
现在,为了将其概括为多个DataFrame,我们迭代循环:
df_list = [x, y]
offset_x = offset_y = 0
for df in df_list:
df.index = np.arange(len(df)) + offset_x
df.columns = np.arange(len(df.columns)) + offset_y
offset_x += df.index[-1] + 1
offset_y += df.columns[-1] + 1
pd.concat(df_list)
0 1 2 3 4
0 1.0 2.0 NaN NaN NaN
1 3.0 4.0 NaN NaN NaN
2 NaN NaN 5 6 7
3 NaN NaN 8 9 X
4 NaN NaN Y Z 0
如果你的索引/列没有单调增加,我强烈建议在连接之前重置它们,或者查看下面的选项。
如果你没有使用0而不是NaN,你可以使用scipy
的{{1}},而无需修改索引或列:
block_diag
此解决方案可归功于this answer。
答案 1 :(得分:2)
作为@ coldpeed scipy.linalg
解决方案的附录,您可以轻松操纵block_diag
算法以使用自定义填充值。
这是一个简化版本:
import numpy as np
def block_diag(*arrs, fillval=0):
arrs = [np.atleast_2d(a) for a in arrs]
shapes = np.array([a.shape for a in arrs])
out_dtype = np.find_common_type([arr.dtype for arr in arrs], [])
out = np.full(np.sum(shapes, axis=0), fill_value=fillval, dtype=out_dtype)
r, c = 0, 0
for i, (rr, cc) in enumerate(shapes):
out[r:r + rr, c:c + cc] = arrs[i]
r += rr
c += cc
return out
df_list = [df1, df2]
res = pd.DataFrame(block_diag(*df_list, fillval=np.nan))
print(res)
0 1 2 3 4
0 1 2 NaN NaN NaN
1 3 4 NaN NaN NaN
2 NaN NaN 5 6 7
3 NaN NaN 8 9 X
4 NaN NaN Y Z 0
我们只需添加一个额外的可选参数并修改以下行,之前使用的是np.zeros
:
out = np.full(np.sum(shapes, axis=0), fill_value=fillval, dtype=out_dtype)