Объединение перекрывающихся наборов данных

Иногда появляется необходимость комбинировать несколько наборов данных, при котором имеющиеся значения одного набора могли бы заменять соответствующие отсутствующие значения другого набора. Например у нас есть две серии:

s1 = pd.Series([0, np.nan, 2, 3, np.nan])
s2 = pd.Series([np.nan, 1, 2, 3, np.nan])

Мы видим, что некоторые пропущенные значения в одной серии, могут быть заменены на имеющиеся значения из другой, а значит было бы круто объединить эти эначения вместе. Это можно сделать с помощью метода combine_first():

s1.combine_first(s2)
0    0.0
1    1.0
2    2.0
3    3.0
4    NaN
dtype: float64

В итоге осталось всего одно значение NaN, которое отсутствует в обеих сериях. Однако, данный метод несколько интереснее чем может показаться. Допустим, в одной серии хранятся свежеполученные данные, но этих данных мало и некоторые из них являются пропущенными, а в другой серии, хранятся не совсем актуальные, но все же полезные данные. Мы конечно можем заменять NaN-ы на среднее или медианное значение, но иногда гораздо целесообразнее заменять их на соответствующие значения из предыдущих выборок. Итак, допустим первый набор данных выглядит так:

data_1 = pd.Series([0, 1, np.nan, 3, 4, np.nan])

А другой, вот так:

data_2 = pd.Series([1, np.nan, 3, np.nan, 9, 5, 4, 1])

Тогда объединить два набора можно так:

data_1.combine_first(data_2)
0    0.0
1    1.0
2    3.0
3    3.0
4    4.0
5    5.0
6    4.0
7    1.0
dtype: float64

Заметьте, что в первом наборе данных NaN-ы были заменены на соответствующие значения из второго набора, а так же к нему в "хвост" добавились данные из второго набора. Иногда такое добавление данных в конец является нежелательным и поэтому в результат можно включить только срез необходимой длины:

data_1.combine_first(data_2)[:len(data_1)]
0    0.0
1    1.0
2    3.0
3    3.0
4    4.0
5    5.0
dtype: float64

Данный метод, пригоден для датафреймов и выполняет комбинирование данных в соответствующих столбцах. Для примера давайте сконструируем два датафрейма:

np.random.seed(5)
data = np.random.choice([11, 11, np.nan], (3, 3))
df1 = pd.DataFrame(data,
                   columns=list('ABC'))
df1
A B C
0 NaN 11.0 NaN
1 NaN 11.0 11.0
2 11.0 11.0 NaN
np.random.seed(15)
data = np.random.choice([22, 22, np.nan], (5, 3))

df2 = pd.DataFrame(data,
                   columns=list('ACD'))
df2
A C D
0 22.0 22.0 22.0
1 22.0 22.0 22.0
2 22.0 NaN 22.0
3 22.0 22.0 22.0
4 NaN NaN 22.0

Что бы дополнить первый датафрейм данными из второго датафрейма достаточно выполнить слудующую команду:

df1.combine_first(df2)
A B C D
0 22.0 11.0 22.0 22.0
1 22.0 11.0 11.0 22.0
2 11.0 11.0 NaN 22.0
3 22.0 NaN 22.0 22.0
4 NaN NaN NaN 22.0

На самом деле combine_first() вызывает более общий метод - DataFrame.combine(), который позволяет задавать собственные функции, определяющие, то как должно выполняться объединение данных.