Конкат DataFrames по диагонали - PullRequest
0 голосов
/ 02 июня 2018

Это вопрос с самостоятельным ответом.Для двух фреймов данных

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. конкатенация двух фреймов данных
  2. конкатенация неопределенного числа фреймов данных (список фреймов данных)

Ответы [ 2 ]

0 голосов
/ 02 июня 2018

В качестве дополнения к решению @ 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)
0 голосов
/ 02 июня 2018

Во-первых, простой случай.Предполагая, что и заголовки, и индексы являются монотонно числовыми, вы можете просто изменить индексаторы 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

Теперь, чтобы обобщить это для нескольких DataFrames, мы повторяем цикл:

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 block_diag без необходимости изменять индексы или столбцы:

from scipy.linalg import block_diag
pd.DataFrame(block_diag(*df_list))

   0  1  2  3  4
0  1  2  0  0  0
1  3  4  0  0  0
2  0  0  5  6  7
3  0  0  8  9  X
4  0  0  Y  Z  0

Кредит этот ответ для этого решения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...