【问题标题】:Fill nan values in test data with mean values form train data in pandas用熊猫训练数据的平均值填充测试数据中的 nan 值
【发布时间】:2019-08-14 12:58:39
【问题描述】:

我正在尝试使用基于列或按列分组的多列上的训练数据的平均值填充测试数据中的 nan 值。以下是部分测试数据:

    date_block_num  shop_id     item_id     item_category_id    target  item_price  avg_item_price  sum_item_cnt_day    avg_item_cnt_day    shop_avg_item_price     ...     avg_item_cnt_day_lag_12     shop_avg_item_price_lag_12  shop_sum_item_cnt_day_lag_12    shop_avg_item_cnt_day_lag_12    category_avg_item_price_lag_12  category_sum_item_cnt_day_lag_12    category_avg_item_cnt_day_lag_12    shop_avg_item_price_per_category_lag_12     shop_sum_item_cnt_per_category_lag_12   shop_avg_item_cnt_per_category_lag_12
0   26.5    5   5037    19.0    0.928571    1788.897788     1934.764286     90.714286   1.937141    868.822366  ...     0.383736    619.341077  181.571429  0.029328    716.813821  779.214286  0.084066    716.052585  10.285714   0.056515
1   NaN     5   5320    NaN     NaN     NaN     NaN     NaN     NaN     NaN     ...     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN
2   30.0    5   5233    19.0    1.428571    854.861715  842.778086  72.428571   1.685456    914.767445  ...     0.000000    597.460870  0.000000    0.000000    591.507516  0.000000    0.000000    591.790514  0.000000    0.000000
3   32.0    5   5232    23.0    0.333333    728.018465  790.297277  47.000000   1.100087    965.966832  ...     0.000000    597.460870  0.000000    0.000000    591.507516  0.000000    0.000000    591.790514  0.000000    0.000000
4   NaN     5   5268    NaN     NaN     NaN     NaN     NaN     NaN     NaN     ...     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN

5 rows × 102 columns

所以我想用基于 item_id 的列的平均值替换 nans。

首先我知道我可以得到按 item_id 分组的火车数据列的平均值,如下所示:

mt = train.groupby('item_id').apply(lambda x: np.mean(x))

然后我看到我尝试对测试集中的每一列使用fillna,如下所示:

for col in test.columns:

    test[col] = test.groupby('item_id')[col].apply(lambda x: x.fillna...)

我不知道如何用火车的平均值替换而不是测试。怎么做?这是最好的方法还是有更好的方法?谢谢。

【问题讨论】:

  • 您能否通过print(df.head()) 并将输出粘贴到您的问题中来提供您作为图片包含的数据?我们可能不需要所有列来回答问题,所以我也会通过以下方式对列进行子选择:df[[date_bock_num, shop_id..]]
  • 我试过了,但是复制粘贴没有正确显示输出。我做到了,但显示不正确。
  • 选择无关紧要。这就是 nans 是如何填充其他集合的值的。任何显示其工作原理的示例都可以。
  • 您的traintest 数据框的形状是否相同?列数和行数一样吗?
  • 在从 train 添加额外功能后只有相同数量的列

标签: python pandas pandas-groupby apply fillna


【解决方案1】:

如果您的 traintest 数据框具有相同的形状(# 行,# 列)

我们可以使用pandas.DataFrame.combine_first 为此,但不能与 groupby 中发生的聚合结合使用,因为 combine_firstNaN 替换为另一个数据帧中相同位置的值。

这就是为什么我们需要为此使用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.transformcombine_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

如果您的 traintest 数据框的形状不同(# rows, # cols), 它变得有点复杂。

我们可以做到以下几点:

  1. 我们可以得到每个item_id 的平均值和pandas.groupby.mean 的值
  2. 之后,我们pandas.DataFrame.merge 将每个对应的item_id 的平均值和train 数据帧的平均值传递给我们的test 数据帧。
  3. 然后,我们对列名进行字典,并有条件地使用来自应用了groupbytrain 数据集的同一列的值填充NaN。我们为此使用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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-16
    • 2016-04-30
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 2020-11-02
    • 2016-01-16
    • 2020-04-26
    相关资源
    最近更新 更多