Я предлагаю следующие шаги:
import pandas as pd
import numpy as np
1 / Разбить каждый фрейм данных (каждая строка повторяется столько раз, сколько снизу вверх)
def explode_df(df, value):
df['interval'] = df['Bottom'] - df['Top'] + 1
df = pd.DataFrame(df.values.repeat(df.Bottom - df.Top, axis=0), columns=df.columns)
df['Top'] = df['Top'] + df.groupby(['ID','Top','Bottom']).cumcount()
return df[['ID', 'Top', value, 'interval']]
df1_expl = explode_df(df1, 'Value_1')
df2_expl = explode_df(df2, 'Value_2')
df1_expl.head(10)
[Out]:
ID Top Value_1 interval
0 A 0 CC 3
1 A 1 CC 3
2 A 2 DD 7
3 A 3 DD 7
4 A 4 DD 7
5 A 5 DD 7
6 A 6 DD 7
7 A 7 DD 7
8 A 10 EE 6
9 A 11 EE 6
2 / Объединить df1_expl и df2_expl по идентификатору и вершине
dfcomb_expl = pd.merge(df1_expl, df2_expl, on=['ID','Top'], how='outer')\
.fillna(0).sort_values(['ID','Top']).reset_index(drop=True)
dfcomb_expl.head(10)
[Out]:
ID Top Value_1 interval_x Value_2 interval_y
0 A 0.0 CC 3 XX 5
1 A 1.0 CC 3 XX 5
2 A 2.0 DD 7 XX 5
3 A 3.0 DD 7 XX 5
4 A 4.0 DD 7 YY 3
5 A 5.0 DD 7 YY 3
6 A 6.0 DD 7 0 0
7 A 7.0 DD 7 0 0
8 A 8.0 0 0 ZZ 13
9 A 9.0 0 0 ZZ 13
3 / Aggregate
a) Создать столбец, равный 1 для каждогосохраняемая строка
dfcomb_expl['keep'] = ((dfcomb_expl['ID'] != dfcomb_expl['ID'].shift()) \
| (dfcomb_expl['Value_1'] != dfcomb_expl['Value_1'].shift()) \
| (dfcomb_expl['Value_2'] != dfcomb_expl['Value_2'].shift()))\
.astype(int)
b) отфильтровать сохраняемые строки
dfcomb = dfcomb_expl[dfcomb_expl['keep']==1].reset_index()
c) вычислить основание и значение_комбинации на основе интерваловрассчитывается на шаге 1
dfcomb['Bottom'] = dfcomb['Top'] + dfcomb_expl.groupby(dfcomb_expl['keep'].cumsum())['ID'].transform('count')
dfcomb['Value_combined'] = np.where(dfcomb['interval_x'] == 0, dfcomb['Value_2'], \
np.where(dfcomb['interval_y'] == 0, dfcomb['Value_1'], \
np.where(dfcomb['interval_x'] < dfcomb['interval_y'], dfcomb['Value_1'], dfcomb['Value_2'])))
df_combine = dfcomb[['ID','Top','Bottom','Value_1','Value_2','Value_combined']]
df_combine
[Out]:
ID Top Bottom Value_1 Value_2 Value_combined
0 A 0.0 2.0 CC XX CC
1 A 2.0 4.0 DD XX XX
2 A 4.0 6.0 DD YY YY
3 A 6.0 8.0 DD 0 DD
4 A 8.0 10.0 0 ZZ ZZ
5 A 10.0 12.0 EE ZZ EE
6 A 15.0 17.0 0 ZZ ZZ
7 B 0.0 2.0 0 NN NN
8 B 3.0 5.0 FF NN NN
9 B 10.0 12.0 FF MM FF
10 B 20.0 25.0 0 MM MM
4 / Примечания В этом решении не учитываются особые случаи, когда Bottom> Top и где для конкретного идентификатора (в df1 или df2) мы имеем2 ряда, включая один и тот же диапазон.