【发布时间】:2020-08-12 21:03:58
【问题描述】:
我需要对一个数据框进行采样,以维护结果中的所有级别的因素。然后我想得到这个样本的补集——即那些不属于样本的行。我的最终目标是为回归分析创建训练和测试样本。为了成功地做到这一点,我需要确保所有级别的因子变量都在训练样本中得到体现。
我尝试过的方法(下面的示例代码)是使用 dplyr::group_by 结合 dplyr::slice_sample 然后 dplyr::anti_join 来获取测试样本。由于某种原因,它不起作用。要么我遗漏了有关这些功能应该如何工作的一些信息,要么它们的行为不符合预期。
我也尝试过基于this question 的方法。它们不起作用,因为 (1) 我需要保证多个因素的所有级别都得到了表示,并且 (2) 我想选择观察的一部分,而不是特定的数字。
示例代码
> library(tidyverse)
>
> set.seed(72)
>
> data <- tibble(y = rnorm(100), x1 = rnorm(100),
+ x2 = sample(letters, 100, T), x3 = sample(LETTERS, 100, T))
> data
# A tibble: 100 x 4
y x1 x2 x3
<dbl> <dbl> <chr> <chr>
1 1.37 -0.737 c C
2 1.16 1.66 c T
3 0.0344 -0.319 q P
4 1.03 -0.963 k C
5 0.636 0.961 i H
6 0.319 0.761 g L
7 0.216 0.860 u M
8 1.31 0.887 g M
9 -0.594 2.70 m I
10 -0.542 0.517 u C
# … with 90 more rows
>
> train_data <- data %>%
+ group_by(x2, x3) %>%
+ slice_sample(prop = .7)
> train_data # clearly this is not what I want
# A tibble: 8 x 4
# Groups: x2, x3 [8]
y x1 x2 x3
<dbl> <dbl> <chr> <chr>
1 1.23 -0.297 c A
2 1.11 0.689 e O
3 0.559 0.353 e Z
4 -1.65 -1.71 l M
5 -0.777 1.31 l X
6 0.784 0.309 s E
7 0.755 -0.362 u X
8 -0.768 0.292 v H
>
> test_data <- data %>%
+ anti_join(train_data)
Joining, by = c("y", "x1", "x2", "x3")
> test_data # my goal was that the training data would have 70% and the test data would have around 30% of the full sample.
# A tibble: 92 x 4
y x1 x2 x3
<dbl> <dbl> <chr> <chr>
1 1.37 -0.737 c C
2 1.16 1.66 c T
3 0.0344 -0.319 q P
4 1.03 -0.963 k C
5 0.636 0.961 i H
6 0.319 0.761 g L
7 0.216 0.860 u M
8 1.31 0.887 g M
9 -0.594 2.70 m I
10 -0.542 0.517 u C
# … with 82 more rows
>
> reg <- lm(y ~ x1 + x2 + x3, train_data)
> predict(reg, newdata = test_data) # I obviously still have the same problem
Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = object$xlevels) :
factor x2 has new levels a, b, d, f, g, h, i, j, k, m, n, o, p, q, r, t, w, x, y, z
>
>
【问题讨论】:
-
一种方法是拒绝抽样。第 1 步:抽取样本,第 2 步检查是否存在所有因子水平。如果是,请继续,如果不是,则拒绝样品并再次抽取。
-
我确信有一种方法可以做到这一点,而无需求助于多次迭代,这会降低我的代码速度——尤其是当我有一个大数据集时。