我有3个未知长度的数据框。
数据框A
如下所示:
A1 A2 n
1 1 2 1
2 3 2 2
3 2 4 3
以类似的方式,数据框B
如下所示:
B1 B2 n
1 3 4 1
2 4 1 2
3 1 3 3
请注意,对于每一行A1,A2,B1,B3都是不同的,并包含1到4的数字。
最后,我有数据框C
:
n C1
1 1 3
2 1 1
3 1 4
4 2 0
5 2 2
6 2 3
7 3 3
8 3 0
9 3 1
请注意,C1的值都在0到4之间。
n
列连接所有数据框。我想要做的是检查C1
的值是A
数据帧还是B
,以及每个n
的值。并在C1中直接替换它。如果值为0,则应保持为0.这是我期待的结果:
n C1
1 1 B
2 1 A
3 1 B
4 2 0
5 2 A
6 2 A
7 3 B
8 3 0
9 3 B
我怎样才能做到这一点?感谢您的投入。
答案 0 :(得分:2)
这是一个想法。我们首先merge
前两个数据帧。在我们merge
之后,我们现在可以通过stack
所有列(n
除外)创建新的数据框。通过创建此新数据框(我们的情况为df5
),我们现在可以match
粘贴n
- value
来自df5
并粘贴n
} - 来自您的第三个数据框的C1
(在我们的例子中为df4
)。然后,简单的gsub
操作只从匹配的值中提取字母。最后一步,我们将NAs设置为0。
df_all <- merge(df2, df3, by = 'n')
# n A1 A2 B1 B2
#1 1 1 2 3 4
#2 2 3 2 4 1
#3 3 2 4 1 3
df5 <- data.frame(n = 1:nrow(df_all), stack(df_all[-1]), stringsAsFactors = FALSE)
#head(df5)
# n values ind
#1 1 1 A1
#2 2 3 A1
#3 3 2 A1
#4 1 2 A2
#5 2 2 A2
#6 3 4 A2
ind <- gsub('\\d+', '', df5$ind)[match(do.call(paste, df4), do.call(paste, df5[-3]))]
ind[is.na(ind)] <- 0
ind
#[1] "B" "A" "B" "0" "A" "A" "B" "0" "B"
答案 1 :(得分:2)
另一种略有不同的方法是首先将A
和B
外部联接到C
,然后找到由等于{{1}的联接添加的列}:
C1
数据:强>
## Do the left outer joins with merge by n and all.x=TRUE
out <- merge(merge(C,A,by="n",all.x=TRUE),B,by="n",all.x=TRUE)
## Loop over rows and extract the name of the column whose value matches C1
## first define a function to do so
extract.name <- function(i,out) {
j <- which(out$C1[i]==out[i,3:ncol(out)])
if (length(j)==0) return("0") else return(substr(colnames(out)[j[1]+2],1,1))
}
## Then, apply it to all rows
out$C1 <- sapply(1:nrow(out),extract.name,out)
## Keep only the n and C1 columns as output
out <- out[,1:2]
## n C1
##1 1 B
##2 1 A
##3 1 B
##4 2 0
##5 2 A
##6 2 A
##7 3 B
##8 3 0
##9 3 B