我听说你并不打算将程序编程风格强加给R.我发现这很难。我刚用for循环解决了一个问题。这是错的吗?是否有更好的,更多的" R风格"溶液
问题:我有两列:Col1和Col2。 Col1包含以自由格式输入的职务。我想使用Col2将这些职位分类收集到类别中(所以"初级技师","工程技术员"和#34;机械技术。"都列为"技术员"
我已经这样做了:
jobcategories<-list(
"Junior Technician|Engineering technician|Mech. tech." = "Technician",
"Manager|Senior Manager|Group manager|Pain in the ****" = "Manager",
"Admin|Administrator|Group secretary" = "Administrator")
for (currentjob in names(jobcategories)) {
df$Col2[grep(currentjob,data$Col1)] <- jobcategories[[currentjob]]
}
这会产生正确的结果,但我不能感觉(因为我的程序经验)我没有正确使用R。 R专家可以让我摆脱痛苦吗?
修改
我被问到原始数据。不幸的是,我无法提供它,因为它有机密信息。它基本上是两列。第一列仅包含400多行不同的职位(以及奇怪的个人姓名)。大约有20种不同的类别可以分成这400种标题。第二列以NA开头,然后在运行for循环后填充。
答案 0 :(得分:7)
你是对的,在R中经常不鼓励for循环,根据我的经验,这有两个主要原因:
正如在R inferno的第2圈中雄辩地描述的那样,一次一个元素生成一个元素可能效率极低,这通常是for循环的诱惑。例如,这是一个非常常见但效率低下的工作流程,因为它会在循环的每次迭代中重新分配output
:
output <- c()
for (idx in indices) {
scalar <- compute.new.scalar(idx)
output <- c(output, scalar)
}
可以通过将output
预先分配到适当的大小并使用for循环或使用类似sapply
的函数来消除此低效率。
低效率的第二个来源是当存在矢量化替代时,在快速操作上执行for循环。例如,请考虑以下代码:
s <- 0
for (elt in x) {
s <- s + elt
}
这是一个非常快速的操作的for循环(添加两个数字),与向量化的sum
函数相比,循环的开销很大,后者将向量中的所有元素相加。 sum
函数很快,因为它是用C实现的,因此执行s <- sum(x)
比使用for循环更有效(更不用说减少输入了)。有时需要更多的创造力来弄清楚如何用快速内部替换for循环和矢量化替代(cumsum
和diff
会出现很多),但它可以带来显着的效率提升。如果你有一个快速循环内部但无法弄清楚如何使用矢量化函数来实现同样的事情,我发现用Rcpp包重新实现循环可以产生更快的替代方案。
如果你不正确地增长对象或者你有一个非常快速的循环内部并且整个事物可以用矢量化操作替换,对于循环可能会很慢。否则你可能不会失去太多效率,因为apply系列函数也在内部执行循环。
答案 1 :(得分:2)
你经常会发现那里有一个非循环的&#39;做事的方式。
例如:
如果您创建一个简单的表格,将旧作业映射到新作业:
job_map <- data.frame(
current = c("Junior Technician", "Engineering technician", "Mech. tech.",
"Manager", "Senior Manager", "Group manager", "Pain in the ****",
"Admin", "Administrator", "Group secretary"),
new = c(rep("Technician",3), rep("Manager",4), rep("Administrator",3))
)
你有一份工作表要重新分类:
my_df <- data.frame(job_name = sample(job_map$current, 50, replace = TRUE))
匹配命令可以帮助您:
my_df$new <- job_map$new[match(my_df$job_name, job_map$current)]
my_df
答案 2 :(得分:1)
for
循环不是'邪恶'&#39;在R中,与基于矢量的方法相比,它们通常很慢,并且通常不是最好的解决方案,但然而它们易于实现且易于理解,您不应低估其中任何一个的价值
因此,在我看来,如果您需要快速完成某项工作并且无法找到更好的方法,那么您应该使用for
循环和 #39; t需要过多担心速度。