簡體   English   中英

R:與應用有關的用戶定義功能問題

[英]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_whendplyr 我沒有使用您的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使用矩陣。 他們的解決方案是一個很好的,但你仍然希望使用功能的情況下,你只需要稍微修改其應用程序並使用adplyplyr庫。 像上面那樣使用示例refinput數據框,而根本不更改函數本身:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM