我有一个这样的数据框:
> 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中相同即可)。目前,我已经使用一系列for
和if
循环完成了它。但是,我想了解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 j
和init
中的值的标签,这只是函数开始向col {{1添加标签的初始值}}。
此时,此函数返回一个数据框,其中只更新了第3列中的前4行(即只有与Column2中j
对应的那些行)。其余的保持不变。
该函数没有返回错误,我肯定知道event2
函数发生了。因此,我假设由于Recall
或return
(或肯定两者)的(不良)使用,该函数无法按预期工作。几个月前我在R中发布了关于递归编程的问题。但我仍然无法正确使用recall
。
因此,问题是:我应该如何在此上下文中使用Recall
,以便输出是上面显示的所需数据框。
谢谢。
答案 0 :(得分:1)
问题在于,在函数的第二次和进一步调用中(通过Recall
),您将丢弃结果。在每个函数调用中对DF
的赋值是分配给数据帧的副本。它适用于循环,因为每次都修改相同的对象。
修复此代码有两种不好的方法。
更改为DF
中的全局作业:
Df[init,j] <<- paste(Df[init,j],node.name, sep="")
...
Df[init+1,j] <<- paste(Df[init+1,j],node.name, sep="")
捕获Recall
的输出并重新分配到DF
:
if (init+1 < nrow(Df)) DF <- Recall(nod = nod+1, j = 3, init = init+1)
第一个是坏的,因为全局分配不起作用,并且通常导致难以发现的错误。第二个是为每次迭代创建一个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="."))