我有一个大的数据集,我需要分为多个平衡集。该集类似于以下内容:
> data<-matrix(runif(4000, min=0, max=10), nrow=500, ncol=8 ) > colnames(data)<-c("A","B","C","D","E","F","G","H")
例如,每个集合包含20行,需要在多个变量之间进行平衡,以便每个子集最终具有与所有其他子集相比包含在其子组中的B、C、D的相似平均值。有没有办法用R做到这一点?任何建议都将不胜感激。提前感谢!
nhjlsmyf1#
library(tidyverse) # Reproducible data set.seed(2) data<-matrix(runif(4000, min=0, max=10), nrow=500, ncol=8 ) colnames(data)<-c("A","B","C","D","E","F","G","H") data=as.data.frame(data)
如果您希望将给定行的观测值放在一起,则可能无法在每列内的集合之间获得相似的均值。(就像你的样本数据一样),你需要25个20行的集合,其中每个A列集合的平均值相同,每个B列集合的平均值相同,等等。这是一个很大的约束。可以找到使集合均值的差最小化的集合成员资格分配调度的算法。但是,如果您可以从每列中分别获取20个观测值,而不考虑它来自哪一行,那么这里有一个选项:x一个一个一个一个x一个一个二个x
一个三个一个x一个四个一个x一个五个一个x一个六个一个如果数据框中的总行数不能被每个集合中所需的行数整除,则可以在创建集合时执行以下操作:
data = data %>% mutate(set = sample(rep(1:ceiling(500/20), each=20))[1:n()])
在这种情况下,集合大小将稍微变化,因为数据行数不能被每个集合中所需的行数整除。
x7rlezfr2#
下面的方法可能值得一试的人在类似的立场。它基于groupdata2的fold()函数中的数值平衡,该函数允许创建具有单个列的平衡均值的组。通过标准化每个列并在数值上平衡它们的行总和,我们可能会增加在单个列中获得平衡均值的机会。我将这种方法与随机分组并选择均值方差最小的分组进行了几次比较,结果似乎更好一些,但我不太相信这种方法在所有情况下都适用。
groupdata2
fold()
# Attach dplyr and groupdata2 library(dplyr) library(groupdata2) set.seed(1) # Create the dataset data <- matrix(runif(4000, min = 0, max = 10), nrow = 500, ncol = 8) colnames(data) <- c("A", "B", "C", "D", "E", "F", "G", "H") data <- dplyr::as_tibble(data) # Standardize all columns and calculate row sums data_std <- data %>% dplyr::mutate_all(.funs = function(x){(x-mean(x))/sd(x)}) %>% dplyr::mutate(total = rowSums(across(where(is.numeric)))) # Create groups (new column called ".folds") # We numerically balance the "total" column data_std <- data_std %>% groupdata2::fold(k = 25, num_col = "total") # k = 500/20=25 # Transfer the groups to the original (non-standardized) data frame data$group <- data_std$.folds # Check the means data %>% dplyr::group_by(group) %>% dplyr::summarise_all(.funs = mean) > # A tibble: 25 x 9 > group A B C D E F G H > <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> > 1 1 4.48 5.05 4.80 5.65 5.04 4.60 5.12 4.85 > 2 2 5.57 5.17 3.21 5.46 4.46 5.89 5.06 4.79 > 3 3 4.33 6.02 4.57 6.18 4.76 3.79 5.94 3.71 > 4 4 4.51 4.62 4.62 5.27 4.65 5.41 5.26 5.23 > 5 5 4.55 5.10 4.19 5.41 5.28 5.39 5.57 4.23 > 6 6 4.82 4.74 6.10 4.34 4.82 5.08 4.89 4.81 > 7 7 5.88 4.49 4.13 3.91 5.62 4.75 5.46 5.26 > 8 8 4.11 5.50 5.61 4.23 5.30 4.60 4.96 5.35 > 9 9 4.30 3.74 6.45 5.60 3.56 4.92 5.57 5.32 > 10 10 5.26 5.50 4.35 5.29 4.53 4.75 4.49 5.45 > # … with 15 more rows # Check the standard deviations of the means # Could be used to compare methods data %>% dplyr::group_by(group) %>% dplyr::summarise_all(.funs = mean) %>% dplyr::summarise(across(where(is.numeric), sd)) > # A tibble: 1 x 8 > A B C D E F G H > <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> > 1 0.496 0.546 0.764 0.669 0.591 0.611 0.690 0.475
最好是比较不同方法对 * 标准化 * 数据的平均值和平均方差(或上述标准差),在这种情况下,可以计算方差之和并使其最小化。
data_std %>% dplyr::select(-total) %>% dplyr::group_by(.folds) %>% dplyr::summarise_all(.funs = mean) %>% dplyr::summarise(across(where(is.numeric), sd)) %>% sum() > 1.643989
fold()函数允许一次创建多个 unique 分组因子(拆分)。因此,在这里,我将执行20次数字平衡拆分,并找到均值标准差之和最小的分组。我将进一步将其转换为函数。
create_multi_balanced_groups <- function(data, cols, k, num_tries){ # Extract the variables of interest # We assume these are numeric but we could add a check data_to_balance <- data[, cols] # Standardize all columns # And calculate rowwise sums data_std <- data_to_balance %>% dplyr::mutate_all(.funs = function(x){(x-mean(x))/sd(x)}) %>% dplyr::mutate(total = rowSums(across(where(is.numeric)))) # Create `num_tries` unique numerically balanced splits data_std <- data_std %>% groupdata2::fold( k = k, num_fold_cols = num_tries, num_col = "total" ) # The new fold column names ".folds_1", ".folds_2", etc. fold_col_names <- paste0(".folds_", seq_len(num_tries)) # Remove total column data_std <- data_std %>% dplyr::select(-total) # Calculate score for each split # This could probably be done more efficiently without a for loop variance_scores <- c() for (fcol in fold_col_names){ score <- data_std %>% dplyr::group_by(!!as.name(fcol)) %>% dplyr::summarise(across(where(is.numeric), mean)) %>% dplyr::summarise(across(where(is.numeric), sd)) %>% sum() variance_scores <- append(variance_scores, score) } # Get the fold column with the lowest score lowest_fcol_index <- which.min(variance_scores) best_fcol <- fold_col_names[[lowest_fcol_index]] # Add the best fold column / grouping factor to the original data data[["group"]] <- data_std[[best_fcol]] # Return the original data and the score of the best fold column list(data, min(variance_scores)) } # Run with 20 splits set.seed(1) data_grouped_and_score <- create_multi_balanced_groups( data = data, cols = c("A", "B", "C", "D", "E", "F", "G", "H"), k = 25, num_tries = 20 ) # Check data data_grouped_and_score[[1]] > # A tibble: 500 x 9 > A B C D E F G H group > <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <fct> > 1 5.86 6.54 0.500 2.88 5.70 9.67 2.29 3.01 2 > 2 0.0895 4.69 5.71 0.343 8.95 7.73 5.76 9.58 1 > 3 2.94 1.78 2.06 6.66 9.54 0.600 4.26 0.771 16 > 4 2.77 1.52 0.723 8.11 8.95 1.37 6.32 6.24 7 > 5 8.14 2.49 0.467 8.51 0.889 6.28 4.47 8.63 13 > 6 2.60 8.23 9.17 5.14 2.85 8.54 8.94 0.619 23 > 7 7.24 0.260 6.64 8.35 8.59 0.0862 1.73 8.10 5 > 8 9.06 1.11 6.01 5.35 2.01 9.37 7.47 1.01 1 > 9 9.49 5.48 3.64 1.94 3.24 2.49 3.63 5.52 7 > 10 0.731 0.230 5.29 8.43 5.40 8.50 3.46 1.23 10 > # … with 490 more rows # Check score data_grouped_and_score[[2]] > 1.552656
通过注解掉num_col = "total"行,我们可以在没有数值平衡的情况下运行它。对我来说,这给出了1.615257的分数。免责声明:我是groupdata2包的作者。fold()函数还可以平衡分类列(cat_col),并将所有ID相同的数据点保存在同一个文件夹(id_col)中(例如,避免交叉验证中的泄漏)。还有一个非常类似的partition()函数。
num_col = "total"
cat_col
id_col
partition()
2条答案
按热度按时间nhjlsmyf1#
如果您希望将给定行的观测值放在一起,则可能无法在每列内的集合之间获得相似的均值。(就像你的样本数据一样),你需要25个20行的集合,其中每个A列集合的平均值相同,每个B列集合的平均值相同,等等。这是一个很大的约束。可以找到使集合均值的差最小化的集合成员资格分配调度的算法。
但是,如果您可以从每列中分别获取20个观测值,而不考虑它来自哪一行,那么这里有一个选项:
x一个一个一个一个x一个一个二个x
一个三个一个x一个四个一个x一个五个一个x一个六个一个
如果数据框中的总行数不能被每个集合中所需的行数整除,则可以在创建集合时执行以下操作:
在这种情况下,集合大小将稍微变化,因为数据行数不能被每个集合中所需的行数整除。
x7rlezfr2#
下面的方法可能值得一试的人在类似的立场。
它基于
groupdata2
的fold()
函数中的数值平衡,该函数允许创建具有单个列的平衡均值的组。通过标准化每个列并在数值上平衡它们的行总和,我们可能会增加在单个列中获得平衡均值的机会。我将这种方法与随机分组并选择均值方差最小的分组进行了几次比较,结果似乎更好一些,但我不太相信这种方法在所有情况下都适用。
最好是比较不同方法对 * 标准化 * 数据的平均值和平均方差(或上述标准差),在这种情况下,可以计算方差之和并使其最小化。
比较多个平衡拆分
fold()
函数允许一次创建多个 unique 分组因子(拆分)。因此,在这里,我将执行20次数字平衡拆分,并找到均值标准差之和最小的分组。我将进一步将其转换为函数。通过注解掉
num_col = "total"
行,我们可以在没有数值平衡的情况下运行它。对我来说,这给出了1.615257的分数。免责声明:我是
groupdata2
包的作者。fold()
函数还可以平衡分类列(cat_col
),并将所有ID相同的数据点保存在同一个文件夹(id_col
)中(例如,避免交叉验证中的泄漏)。还有一个非常类似的partition()
函数。