Если ваши train
и test
данные имеют одинаковую форму (# строк, # столбцов)
Мы можем использовать pandas.DataFrame.combine_first
для этого, но не в сочетании с агрегацией, которая происходит в groupby
, поскольку combine_first
заменяет NaN
значениями в той же позиции в другом кадре данных.
Вот почему нам нужно использовать pandas.DataFrame.transform
для этого, поскольку он сохраняет shape
нашего фрейма данных таким же:
# make two example dataframes
train = pd.DataFrame({'item_id':[5037, 5320, 5037, 5320],
'num1': [10, 8, 9, 5],
'num2': [3, 5, 1, 9]})
test = pd.DataFrame({'item_id':[5037, 5320, 5037, 5320],
'num1': [6, np.NaN, 3, 7],
'num2': [np.NaN, 4, np.NaN, 9]})
print(train, '\n')
print(test)
item_id num1 num2
0 5037 10 3
1 5320 8 5
2 5037 9 1
3 5320 5 9
item_id num1 num2
0 5037 6.0 NaN
1 5320 NaN 4.0
2 5037 3.0 NaN
3 5320 7.0 9.0
Мы применяем groupby.transform
и combine_first
train_means = train.groupby('item_id').transform('mean')
test.combine_first(train_means)
item_id num1 num2
0 5037 6.0 2.0
1 5320 6.5 4.0
2 5037 3.0 2.0
3 5320 7.0 9.0
Если ваш train
и test
кадр данных НЕ имеют одинаковую форму (# строки, # столбцы) ,
это становится немного сложнее.
Мы можем сделать следующее:
- Мы можем получить среднее значение для каждого
item_id
и valeus с pandas.groupby.mean
- После этого мы
pandas.DataFrame.merge
получаем средства каждого соответствующего item_id
и среднего train
кадра данных на наш test
кадр данных.
- Затем мы определяем имена наших столбцов и условно заполняем наш
NaN
значениями того же столбца, который взят из нашего набора данных train
, к которому применен groupby
. И для этого мы используем np.where
.
train_grp = train.groupby('item_id').mean().reset_index()
print(train_grp)
item_id num1 num2
0 5037 9.5 2.0
1 5320 6.5 7.0
Применить слияние
test_merged = test.merge(train_grp, on='item_id', suffixes=['_test', '_train'])
print(test_merged)
item_id num1_test num2_test num1_train num2_train
0 5037 6.0 NaN 9.5 2.0
1 5037 3.0 NaN 9.5 2.0
2 5320 NaN 4.0 6.5 7.0
3 5320 7.0 9.0 6.5 7.0
Создать словарь соответствующих столбцов
test_cols = [col for col in test_merged.columns if 'test' in col]
train_cols = [col for col in test_merged.columns if 'train' in col]
dict_cols =dict(zip(test_cols, train_cols))
print(dict_cols)
{'num1_test': 'num1_train', 'num2_test': 'num2_train'}
Условно заменить Nan
for test, train in dict_cols.items():
test_merged[test] = np.where(test_merged[test].isnull(),
test_merged[train],
test_merged[test])
# Clean up dataframe
test_merged.drop(train_cols, axis=1, inplace=True)
test_merged.columns = test_merged.columns.str.replace('_test', '')
print(test_merged)
item_id num1 num2
0 5037 6.0 2.0
1 5037 3.0 2.0
2 5320 6.5 4.0
3 5320 7.0 9.0
Объяснение
np.where
работает следующим образом: np.where(condition, value if true, value if false)