Concat DataFrames对角

时间:2018-06-02 17:50:58

标签: python pandas dataframe concatenation

这是一个自我回答的问题。给定两个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

最简单最简单的方法是什么?我想考虑两种情况:

  1. 连接两个dataFrames
  2. 连接未指定数量的dataFrames(DataFrames列表)

2 个答案:

答案 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)