[英]R: user-defined function issue with apply
我有2個檔案。
“ increment.tab”
grp increment
1 10
2 25
3 35
4 50
“ input.tab”
grp pos
1 10
1 14
1 25
2 3
2 20
3 2
3 10
我試圖將增量應用於“ input.tab”的第2列,例如:
if grp=1, then increment=0
if grp=2, then increment=10
if grp=3, then increment=10+25=35
if grp=4, then increment=10+25+35=70
...
為了獲得此輸出:
grp pos pos_adj
1 10 10
1 14 14
1 25 25
2 3 13
2 20 30
3 2 37
3 10 45
我的計划是使用apply
逐行處理輸入文件:
ref <- read.table("increment.tab", header=T, sep="\t")
input <- read.table("input.tab", header=T, sep="\t")
my_fun <- function(x, y){
if(x==1){
inc=0
}
else{
inc=sum(ref[1:match(x, ref$grp)-1,2])
}
result = y + inc
return(result)
}
input$pos_adj = apply(input, 1, my_fun(input$grp, input$pos))
但是我收到了我無法真正理解的錯誤消息。
Error in match.fun(FUN) :
'my_fun(input$grp, input$pos)' is not a function, character or symbol
In addition: Warning message:
In if (x == 1) { :
the condition has length > 1 and only the first element will be used
為什么“ my_fun”不被視為函數?
您的apply
調用失敗,因為您的第三個參數是函數調用的結果,而不是函數本身。 此外,盡管它可以在您提供基本數據的情況下工作,但是如果data.frame中存在任何其他數據類型,則它將失敗,因為apply
將data.frame轉換為matrix
,這將導致類型轉換。 由於這個原因(以及其他一些原因),我建議您不要在此處使用apply
。
我認為您可以很容易地對其進行向量化,並且可以通過merge
解決引入基於grp
的附加項的技巧。 (也可以使用dplyr::left_join
來完成。)
您的數據:
increment <- read.table(text = "grp increment
1 10
2 25
3 35
4 50", header = TRUE)
input <- read.table(text = "grp pos
1 10
1 14
1 25
2 3
2 20
3 2
3 10", header = TRUE)
我將對其進行更新,以使調整基於$increment
列。 您可以替換 $increment
而不是添加 $add
。
increment$add <- c(0, cumsum(increment$increment[-nrow(increment)]))
increment
# grp increment add
# 1 1 10 0
# 2 2 25 10
# 3 3 35 35
# 4 4 50 70
x <- merge(input, increment[,c("grp", "add")], by = "grp")
x
# grp pos add
# 1 1 10 0
# 2 1 14 0
# 3 1 25 0
# 4 2 3 10
# 5 2 20 10
# 6 3 2 35
# 7 3 10 35
從這里開始,只需要進行調整即可。 這兩個都是
x$pos_adj <- x$pos + x$add
x$add <- NULL # remove the now-unnecessary column
x
# grp pos pos_adj
# 1 1 10 10
# 2 1 14 14
# 3 1 25 25
# 4 2 3 13
# 5 2 20 30
# 6 3 2 37
# 7 3 10 45
(我對列等有點冗長。當然可以使它緊湊一些,但是我希望有空間了解正在執行的操作以及在何處執行。)
這是使用case_when
的dplyr
。 我沒有使用您的crement.tab,因為數字與您的示例不匹配。
dplyr版本0.5.0
library(dplyr)
input.tab%>%
mutate(pos_adj=case_when(.$grp==1 ~ .$pos+0,
.$grp==2 ~ .$pos+10,
.$grp==3 ~ .$pos+35,
.$grp==4 ~ .$pos+70))
grp pos pos_adj
1 1 10 10
2 1 14 14
3 1 25 25
4 2 3 13
5 2 20 30
6 3 2 37
7 3 10 45
dplyr版本0.7.0
library(dplyr)
input.tab%>%
mutate(pos_adj=case_when(grp==1 ~ pos+0,
grp==2 ~ pos+10,
grp==3 ~ pos+35,
grp==4 ~ pos+70))
數據
input.tab <- read.table(text="grp pos
1 10
1 14
1 25
2 3
2 20
3 2
3 10",header=TRUE,stringsAsFactors=FALSE)
首先創建一個向量以從中查找值
vec = setNames(object = c(0, 10, 35, 70), nm = c(1, 2, 3, 4))
vec
# 1 2 3 4
# 0 10 35 70
然后,從vec
查找適當的值並將其添加到pos
。 使用Lapointe的數據
increment.tab$pos + vec[match(increment.tab$grp, names(vec))]
# 1 1 1 2 2 3 3
#10 14 25 13 30 37 45
您已經接近了,但是正如@ r2evans所解釋的那樣,您的函數調用存在問題,並且apply
使用矩陣。 他們的解決方案是一個很好的,但你仍然希望使用功能的情況下,你只需要稍微修改其應用程序並使用adply
從plyr
庫。 像上面那樣使用示例ref
和input
數據框,而根本不更改函數本身:
new_df <- adply(input, 1, function(df){
c(pos_adj = my_fun(df$grp, df$pos))
})
> new_df
grp pos pos_adj
1 1 10 10
2 1 14 14
3 1 25 25
4 2 3 13
5 2 20 30
6 3 2 37
7 3 10 45
如果您希望堅持apply
,則可以選擇以下方法(同樣,不更改功能):
input$pos_adj <- apply(input, 1, function(df){
my_fun(df["grp"], df["pos"])
})
> input
grp pos pos_adj
1 1 10 10
2 1 14 14
3 1 25 25
4 2 3 13
5 2 20 30
6 3 2 37
7 3 10 45
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.