【问题标题】:want to avoid for loop in r and use one of the apply functions想要避免 r 中的 for 循环并使用其中一个应用函数
【发布时间】:2016-07-27 21:31:04
【问题描述】:

应该使用哪个 apply 函数来避免下面代码中的 for 循环?变量标签现在是简单的占位符 - 目标是使用此过程在 R 中设置密码本,以便轻松导出到 SPSS,在 SPSS 中打开密码本即可使用。理想情况下,这将简化我在 R 中为自己的工作工作的能力,但与使用 SPSS 的同事兼容。

data1 <- read.table(header = TRUE, sep=",",
                   text = "
SubjectID,Age,WeightPRE,WeightPOST,Height,SES,GenderSTR,GenderCoded
1,45,150,145,5.6,2,m,1
2,50,167,166,5.4,2,f,2
3,35,143,135,5.6,2,F,2
4,44,216,201,5.6,2,m,1
5,32,243,223,6,2,m,1
6,48,165,145,5.2,2,f,2
7,50,132,132,5.3,2,m,1
8,51,110,108,5.1,3,f,2
9,46,167,158,5.5,2,,
10,35,190,200,5.8,1,Male,1
11,36,230,210,6.2,1,m,1
12,40,200,195,6.1,1,f,2
13,45,180,185,5.9,3,f,2
14,52,240,220,6.5,2,m,1
15,24,250,240,6.4,2,M,1
16,35,175,174,5.8,2,F,2
17,51,220,221,6.3,2,m,1
18,43,230,215,2.6,2,m,1
19,36,190,180,5.7,1,female,2
20,44,260,240,6.4,3,male,1
")

var.labels = c(SubjectID="aaa",
               Age="Age in Years", 
               WeightPRE="bbb",
               WeightPOST="ccc",
               Height="ddd",
               SES="eee",
               GenderSTR="fff",
               GenderCoded="ggg")

for(i in 1:8){
  attr(dtab1[[names(var.labels)[i]]],"label") <- var.labels[names(var.labels)[i]]
}

# using the haven package
# this creates SPSS datafile with variable labels
library(haven)
write_sav(dtab1,"out1.sav")

【问题讨论】:

  • 这种情况下的 for 循环是完全可以接受的,但您应该将可迭代值从 1:8 更改为 1:length(var.labels) 以保持通用性。您是否有不想使用 for 循环的原因。

标签: r for-loop apply r-haven


【解决方案1】:

感谢lmo 的建议。

主要是我想尽可能避免 for 循环 - 但我认为你是对的,在这种情况下 for 循环可能可以使用。我刚刚使用microbenchmark 包进行了系统时间分析,得到了以下结果...

library(microbenchmark)
microbenchmark(
  data1[] <- lapply(1:8, function(i) {
    # assign the label
    attr(data1[[names(var.labels)[i]]], "label") <-
      var.labels[names(var.labels)[i]]
    # return the vector
    data1[[names(var.labels)[i]]]
  })
)

导致:

Unit: microseconds expr data1[] <- lapply(1:8, function(i) { attr(data1[[names(var.labels)[i]]], "label") <- var.labels[names(var.labels)[i]] data1[[names(var.labels)[i]]] }) min lq mean median uq max neval 380.291 412.986 638.6603 445.2185 661.102 2863.767 100

for 循环运行得更快...

microbenchmark(
  for(i in 1:8){
    attr(data1[[names(var.labels)[i]]],"label") <- var.labels[names(var.labels)[i]]
  }
)

给出了这个时间分析:

Unit: microseconds expr for (i in 1:8) { attr(data1[[names(var.labels)[i]]], "label") <- var.labels[names(var.labels)[i]] } min lq mean median uq max neval 179.015 197.798 289.9299 209.624 278.7255 1186.783 100

感谢您对我的问题的反馈和考虑。

【讨论】:

    【解决方案2】:

    在这种情况下,for 循环可能是添加此材料的最佳方法。例如,这是使用lapply 添加此材料的大致“最佳”方式:

    data1[] <- lapply(1:8, function(i) {
                                    # assign the label
                                    attr(data1[[names(var.labels)[i]]], "label") <-
                                         var.labels[names(var.labels)[i]]
                                    # return the vector
                                    data1[[names(var.labels)[i]]]
                })
    

    在我看来,这不太容易阅读,并且相对于您的 for 循环涉及一些不必要的拉伸。

    【讨论】:

      【解决方案3】:

      至于循环被认为是不错的选择,这里是循环本身的一个小改进:

      for(var in names(var.labels)) {
        attr(data1[[var]], "label") <- var.labels[var]
      }
      

      改进包括:

      • 可根据需要推广到尽可能多的标签
      • 如果您忽略为任何变量创建标签,也不会遇到问题
      • 代码更短,更易阅读(至少对我而言)

      【讨论】:

      • 感谢 Simon 提供了更简洁、更通用的代码!
      猜你喜欢
      • 1970-01-01
      • 2011-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-26
      • 1970-01-01
      相关资源
      最近更新 更多