r - R语言:处理数据框中数据的函数
问题描述
场景是有一个函数从数据框中的列中获取值,进行一些处理并用结果填充另一列。
这是用于测试的简化版本:
#the function checks if the value in inVar1 exists.
#if it does then it returns the value, if not it returns -100
#inRow: for debugging
test2 <- function (inVar1,inRow)
{
#debug
print(paste("Row=",inRow, " inVar1=", inVar1, sep=''))
if(is.na(inVar1) || is.null(inVar1))
{
#debug
print("position 1")
ret <- -100
}
else
{
#debug
print("position 2")
ret <- inVar1
}
#debug
print("position 3")
return(ret)
}
简单的功能测试:
> a <- test2(7,1)
[1] "Row=1 inVar1=7"
[1] "position 2"
[1] "position 3"
> print(a)
[1] 7
>
> a <- test2(NA,1)
[1] "Row=1 inVar1=NA"
[1] "position 1"
[1] "position 3"
> print(a)
[1] -100
它按预期工作。
现在让我们创建一个数据框
> d1 <- data.frame(rowID=c(1,2,3), var1=c(2,NA,5))
> print(d1)
rowID var1
1 1 2
2 2 NA
3 3 5
让我们测试从数据框中传递值的函数:
> a <- test2(d1[1,2],d1[1,1])
[1] "Row=1 inVar1=2"
[1] "position 2"
[1] "position 3"
> print(a)
[1] 2
> a <- test2(d1[2,2],d1[2,1])
[1] "Row=2 inVar1=NA"
[1] "position 1"
[1] "position 3"
> print(a)
[1] -100
> a <- test2(d1[3,2],d1[3,1])
[1] "Row=3 inVar1=5"
[1] "position 2"
[1] "position 3"
> print(a)
[1] 5
同样,它按预期工作。
现在,最后一件事。我想添加一个包含已处理值的新列。
d1$var2 <- test2(d1$var1,d1$rowID)
print(d1)
这会产生以下输出:
> d1$var2 <- test2(d1$var1,d1$rowID)
[1] "Row=1 inVar1=2" "Row=2 inVar1=NA" "Row=3 inVar1=5"
[1] "position 2"
[1] "position 3"
> print(d1)
rowID var1 var2
1 1 2 2
2 2 NA NA
3 3 5 5
第 1 行和第 3 行中 var2 的值按预期计算,但在第 2 行中它是 NA 而不是预期的 -100。
我做错了什么?
我不明白的另一件事是为什么我们只看到一次调试消息,而不是根据行数,即三次?
谢谢!
解决方案
您的函数未矢量化。您通过 1 对数字 3 次,每行一个,这是正确的,而您的最终测试通过 1 对向量一次;每个变量有 1 个向量。为了使您的功能正常工作,您需要一次喂它一对。mapply 会为您做到这一点。
d1$var2 <- mapply(FUN = test2,inVar1 = d1$var1,inRow = d1$rowID)
但总的来说,您可能需要在考虑矢量化的情况下重写您的函数。
# "vectorised in the sense that it can operate on entire vectors at once"
test2vectbasic <- function(inVar1,inRow){
# using mapply, but could be a basic for loop too
mapply(FUN = test2,inVar1 = inVar1,inRow = inRow)
}
# efficient R vectorization that uses built in low level language loops
# using "existing R functions that are already vectorised"
test2vectbetter <- function(inVar1){
ifelse(is.na(inVar1) | is.null(inVar1),-100,inVar1)
}
# sample data
d1 <- data.frame(rowID=c(1,2,3), var1=c(2,NA,5))
# mapply way
d1$var2 <- mapply(FUN = test2,inVar1 = d1$var1,inRow = d1$rowID)
# basic way on atoms or vectors
test2vectbasic(d1[2,2],d1[2,1])
d1$var3 <- test2vectbasic(d1$var1,d1$rowID)
# efficient way
test2vectbetter(d1[2,2],d1[2,1])
d1$var4 <- test2vectbetter(d1$var1)
要获得您想要的功能,您至少需要基本的矢量化。关于矢量化的一些资源:
R inferno - 进入地狱的第三圈 - 无法矢量化
推荐阅读
- android - EdgeLight:屏幕边框不会超出反应原生的缺口和软键
- jquery - 使用 AJAX 从 HTML 表中插入大量行的最佳方法
- python - 显示具有自定义颜色的数组
- .net - 长时间运行的 SQL Server 报告,如何在异步模式下运行它们
- regex - 正则表达式与 ${} 内允许的句点精确匹配一个 alpha 字符串
- sql - SQL Developer:在查询结果的变量中保存多个值
- python - 检查输入是否全部为大写和数字
- c++ - c++ 全局变量初始化(initializer_list的向量)
- javascript - 如何使用 Firebase 托管重定向网站的主页
- django - 如何在 SlugRelatedField 中使用相关字段?