【问题标题】:stratified splitting the data分层拆分数据
【发布时间】:2014-01-13 15:22:12
【问题描述】:

我有一个大型数据集,喜欢为每个城市拟合不同的逻辑回归,这是我数据中的一列。以下 70/30 拆分在不考虑城市组的情况下有效。

indexes <- sample(1:nrow(data), size = 0.7*nrow(data))

train <- data[indexes,]
test <- data[-indexes,]

但这并不能保证每个城市都有 70/30 的比例。

假设我有城市 A 和城市 B,其中城市 A 有 100 行,城市 B 有 900 行,总共 1000 行。使用上面的代码拆分数据将为我提供 700 行用于火车和 300 行用于测试数据,但它不能保证我将在火车数据中为城市 A 提供 70 行,为城市 B 提供 630 行。我该怎么做?

一旦我将每个城市的训练数据拆分为 70/30 时尚,我将为每个城市运行逻辑回归(一旦我有了训练数据,我就知道该怎么做)

【问题讨论】:

  • 您需要将 lapply 调用的输出分配给对象名称。 R 是一种函数式语言。函数返回值,但如果您不保存它们,它们将被垃圾回收。

标签: r split logistic-regression


【解决方案1】:

caret 包中尝试createDataPartition。其文档指出:默认情况下,createDataPartition 对数据进行分层随机拆分。

library(caret)
train.index <- createDataPartition(Data$Class, p = .7, list = FALSE)
train <- Data[ train.index,]
test  <- Data[-train.index,]

它也可以用于分层K-fold,如:

ctrl <- trainControl(method = "repeatedcv",
                     repeats = 3,
                     ...)
# when calling train, pass this train control
train(...,
      trControl = ctrl,
      ...)

查看caret文档了解更多详情

【讨论】:

    【解决方案2】:

    splitstackshape 有一个很好的函数stratified 也可以做到这一点,但这比createDataPartition 好一点,因为它可以一次使用多个列进行分层。它可以与一列一起使用,例如:

    library(splitstackshape)
    set.seed(42)  # good idea to set the random seed for reproducibility
    stratified(data, c('City'), 0.7)
    

    或多列:

    stratified(data, c('City', 'column2'), 0.7)
    

    【讨论】:

      【解决方案3】:

      典型的方式是split

      lapply( split(dfrm, dfrm$City), function(dd){
                  indexes= sample(1:nrow(dd), size = 0.7*nrow(dd))
                  train= dd[indexes, ]    # Notice that you may want all columns
                  test= dd[-indexes, ]
                  # analysis goes here
                  }
      

      如果您按照上面的尝试按步骤进行操作,将是这样的:

      cities <- split(data,data$city)
      
      idxs <- lapply(cities, function (d) {
          indexes <- sample(1:nrow(d), size=0.7*nrow(d))
      })
      
      train <- data[ idxs[[1]], ]  # for the first city
      test <-  data[ -idxs[[1]], ]
      

      我碰巧认为这是一种笨拙的方法,但也许将其分解为小步骤可以让您检查中间值。

      【讨论】:

      • 感谢您的留言,但我认为这不起作用。训练和测试数据集中没有数据。
      • 将“数据”更改为“dd”。
      • 对。它会在函数调用中创建这些对象,但返回的内容取决于分析。如果您只是运行该函数,那么它可能会或可能不会返回任何内容。此外,结果没有分配任何东西。你从来没有说过你想要做什么分析,所以我只是放了一个占位符。
      • 只会返回该分配的 RHS 值。不应有任何名为“索引”的对象。我最近的代码使用[[.]] 从列表中拉出一个向量。
      • Ishouldbuyaoat:一旦我得到火车数据,我将为每个城市运行逻辑回归,如下所示:city_2
      【解决方案4】:

      您的代码可以正常工作,如果 City 是一列,只需将训练数据作为 train[,2] 运行。您可以使用 lambda 函数轻松地为每个人完成此操作

      logReg<-function(ind) {
          reg<-glm(train[,ind]~WHATEVER)
          ....
          return(val) }
      

      然后在城市索引的向量上运行 sapply。

      【讨论】:

      • 是的,对我来说,它也应该工作,但它不起作用。训练或测试数据不存在。
      • 你能验证索引是正确的吗?我只是在一些数据上对其进行了测试,对我来说效果很好,不确定是什么问题
      【解决方案5】:

      另一种可能的方式,类似于 IRTFM 的答案(例如,仅使用 base-r)是使用以下内容。请注意,此答案返回一个分层索引,可以像问题中计算的索引一样使用。

      p <- 0.7
      strats <- your_data$the_stratify_variable
      
      rr <- split(1:length(strats), strats)
      idx <- sort(as.numeric(unlist(sapply(rr, function(x) sample(x, length(x) * p)))))
      
      train <- your_data[idx, ]
      test <- your_data[-idx, ]
      

      例子:

      p <- 0.7
      strats <- mtcars$cyl
      
      rr <- split(1:length(strats), strats)
      idx <- sort(as.numeric(unlist(sapply(rr, function(x) sample(x, length(x) * p)))))
      
      train <- mtcars[idx, ]
      test <- mtcars[-idx, ]
      
      table(mtcars$cyl) / nrow(mtcars)
      #>       4       6       8
      #> 0.34375 0.21875 0.43750 
      
      table(train$cyl) / nrow(train)
      #>    4    6    8
      #> 0.35 0.20 0.45 
      
      table(test$cyl) / nrow(test)
      #>         4         6         8 
      #> 0.3333333 0.2500000 0.4166667 
      

      我们看到所有数据集(mtcars)、训练和测试都具有大致相同的类分布!

      【讨论】:

        猜你喜欢
        • 2020-09-25
        • 2023-01-22
        • 2022-06-25
        • 2020-11-19
        • 2019-11-17
        • 2019-07-19
        • 2017-12-25
        • 2012-09-09
        • 2021-02-03
        相关资源
        最近更新 更多