理解R中的Recall功能

时间:2014-12-22 20:34:55

标签: r recursion

我有一个这样的数据框:

> Df
   X1     X2     X3
1  event1 event2 event5
2  event1 event2 event5
3  event1 event2 event6
4  event1 event2 event6
5  event1 event3 event7
6  event1 event3 event7
7  event1 event3 event7
8  event1 event4 event7
9  event1 event4 event7
10 event1 event4 event7

(真实数据框包含超过20个cols和数千行)。

我的目标是在column3中添加一个标签,以便我知道Column3中哪个事件与Column3中的事件相关联。 "关联"这意味着,对于行和列i + 1和j + 1,行和列i和j的事件是什么。也就是说,此处的最终data.frame应如下所示:

> final.Df
   X1     X2     X3
1  event1 event2 event5.n1
2  event1 event2 event5.n1
3  event1 event2 event6.n1
4  event1 event2 event6.n1
5  event1 event3 event7.n2
6  event1 event3 event7.n2
7  event1 event3 event7.n2
8  event1 event4 event7.n3
9  event1 event4 event7.n3
10 event1 event4 event7.n3

(注意,如果Col2中的事件相同,则n1,n2或n3是任意的,只要在Col3中相同即可)。目前,我已经使用一系列forif循环完成了它。但是,我想了解R中的Recall函数,并以更紧凑的方式对其进行编码。

为此,我写了这个函数:

rename.cols <- function(nod = 1, j = 3, init =1) {
    ##generating labels to add
    node.name <- paste(".n", nod, sep = "") 
    ##adding label to 1st row in each block 
    Df[init,j] <- paste(Df[init,j],node.name, sep="") 
    ##adding labels in col j while elements in col j-1 are identical
    while (init+1 <= nrow(Df) & Df[init+1,j-1] == Df[init,j-1]){
        Df[init+1,j] = paste(Df[init+1,j],node.name, sep="")
        init = init + 1
    }
    ##while the end of the Df is not reached, Recall the function again
    ##using updated parameters
    if (init+1 < nrow(Df)) Recall(nod = nod+1, j = 3, init = init+1)
    else print("end")
    return(Df)
}

其中nod用于创建要添加到col jinit中的值的标签,这只是函数开始向col {{1添加标签的初始值}}。

此时,此函数返回一个数据框,其中只更新了第3列中的前4行(即只有与Column2中j对应的那些行)。其余的保持不变。

该函数没有返回错误,我肯定知道event2函数发生了。因此,我假设由于Recallreturn(或肯定两者)的(不良)使用,该函数无法按预期工作。几个月前我在R中发布了关于递归编程的问题。但我仍然无法正确使用recall

因此,问题是:我应该如何在此上下文中使用Recall,以便输出是上面显示的所需数据框。

谢谢。

2 个答案:

答案 0 :(得分:1)

问题在于,在函数的第二次和进一步调用中(通过Recall),您将丢弃结果。在每个函数调用中对DF的赋值是分配给数据帧的副本。它适用于循环,因为每次都修改相同的对象。

修复此代码有两种不好的方法。

  1. 更改为DF中的全局作业:

    Df[init,j] <<- paste(Df[init,j],node.name, sep="") ... Df[init+1,j] <<- paste(Df[init+1,j],node.name, sep="")

  2. 捕获Recall的输出并重新分配到DF

    if (init+1 < nrow(Df)) DF <- Recall(nod = nod+1, j = 3, init = init+1)

  3. 第一个是坏的,因为全局分配不起作用,并且通常导致难以发现的错误。第二个是为每次迭代创建一个DF的新副本。

    循环是此任务的适当结构。递归只是模拟一个循环。

答案 1 :(得分:-1)

这是使用dplyr和stringr的简单解决方案

library(tidyverse)
x1<-rep("e1",10)
x2<-c(rep("e2",4),rep("e3",3),rep("e4",3))
x3<-c(rep("e5",2),rep("e6",2),rep("e7",6))
df<-as.tibble(cbind(x1,x2,x3))

df%>%
group_by(x2)%>%
mutate(x3=str_c(x3,x2,sep="."))