【问题标题】:How can I ensure that a partition has representative observations from each level of a factor?如何确保分区具有来自因子的每个级别的代表性观察?
【发布时间】:2013-05-05 19:50:00
【问题描述】:

我编写了一个小函数来将我的数据集划分为训练集和测试集。但是,我在处理因子变量时遇到了麻烦。在我的代码的模型验证阶段,如果模型建立在一个没有来自每个因子级别的表示的数据集上,我会收到错误消息。如何修复此 partition() 函数以包含来自因子变量每个级别的至少一个观察值?

test.df <- data.frame(a = sample(c(0,1),100, rep = T),
                      b = factor(sample(letters, 100, rep = T)),
                      c = factor(sample(c("apple", "orange"), 100, rep = T)))

set.seed(123)
partition <- function(data, train.size = .7){
  train <- data[sample(1:nrow(data), round(train.size*nrow(data)), rep= FALSE), ]
  test <- data[-as.numeric(row.names(train)), ]
  partitioned.data <- list(train = train, test = test)
  return(partitioned.data)
}

part.data <- partition(test.df)
table(part.data$train[,'b'])
table(part.data$test[,'b'])

编辑 - 使用“caret”包和 createDataPartition() 的新函数:

partition <- function(data, factor=NULL, train.size = .7){
  if (("package:caret" %in% search()) == FALSE){
    stop("Install and Load 'caret' package")
  }
  if (is.null(factor)){
    train.index <- createDataPartition(as.numeric(row.names(data)),
                                       times = 1, p = train.size, list = FALSE)
    train <- data[train.index, ]
    test <- data[-train.index, ]
  }
  else{
    train.index <- createDataPartition(factor,
                                       times = 1, p = train.size, list = FALSE)
    train <- data[train.index, ]
    test <- data[-train.index, ]
  }
  partitioned.data <- list(train = train, test = test)
  return(partitioned.data)
}

【问题讨论】:

  • 我知道这并不能回答您的问题,但是以如此少量的观察值作为因子变量的条件甚至是一个好主意吗?这些估计肯定会非常不精确,并且可能会使您的样本外预测变得更糟而不是更好。
  • 你说得对,这是一个坏主意。但是,在实践中,我永远不会在这么小的数据集上使用这个函数。我把它变小了,这样分区的 test.df 几乎可以保证有一些观察值为 0 的因素。
  • 我有同样的问题,但似乎第二个partition 函数定义一次只适用于一个因素。我理解您的问题是关于在train 数据集中有一个分区,其中包含输入列的所有级别的因素:bc,但createDataPartition 仅适用于一列,例如:partition(test.df, factor = test.df[, c("b", "c")])不工作。

标签: r statistics partitioning factors categorical-data


【解决方案1】:

试试 caret 包,尤其是函数createDataPartition()。它应该完全满足您的需求,可在 CRAN 上找到,主页在这里:

caret - data splitting

我提到的函数部分是我在网上找到的一些代码,然后我稍微修改了它以更好地处理边缘情况(比如当您要求样本量大于集合或子集时)。

stratified <- function(df, group, size) {
  # USE: * Specify your data frame and grouping variable (as column
  # number) as the first two arguments.
  # * Decide on your sample size. For a sample proportional to the
  # population, enter "size" as a decimal. For an equal number
  # of samples from each group, enter "size" as a whole number.
  #
  # Example 1: Sample 10% of each group from a data frame named "z",
  # where the grouping variable is the fourth variable, use:
  #
  # > stratified(z, 4, .1)
  #
  # Example 2: Sample 5 observations from each group from a data frame
  # named "z"; grouping variable is the third variable:
  #
  # > stratified(z, 3, 5)
  #
  require(sampling)
  temp = df[order(df[group]),]
  colsToReturn <- ncol(df)

  #Don't want to attempt to sample more than possible
  dfCounts <- table(df[group])
  if (size > min(dfCounts)) {
    size <- min(dfCounts)
  }



  if (size < 1) {
    size = ceiling(table(temp[group]) * size)
  } else if (size >= 1) {
    size = rep(size, times=length(table(temp[group])))
  }
  strat = strata(temp, stratanames = names(temp[group]),
                 size = size, method = "srswor")
  (dsample = getdata(temp, strat))

  dsample <- dsample[order(dsample[1]),]
  dsample <- data.frame(dsample[,1:colsToReturn], row.names=NULL)
  return(dsample)

}

【讨论】:

  • 我去看看。我以前听说过,但从未使用过。
  • 告诉我。我还有另一个函数,我也可以给你代码。
  • 很高兴看到您的功能...我仍然有一些问题。我隔离了 createDataPartition() 中弄乱我的部分,但我不确定如何修复它。这就有点像“是否值得用一个观察值构建一个使用许多因素的模型?”
  • 当然,我应该单独回答吗?
  • 我是原作者,你很有可能从 SO 上的答案中得到它,因为我会在那里发布使用“采样”包的版本。从那时起,有两个改进版本:a data.frame onea data.table one(虽然后者需要最新的“data.table”开发版本,但速度非常快)。
猜你喜欢
  • 2022-11-04
  • 2020-08-31
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2022-10-22
  • 1970-01-01
  • 2014-03-20
  • 1970-01-01
相关资源
最近更新 更多