使用这种基本方法有两个大思路:
- 由于我们需要比较所有值,因此我们应该将所有内容重新组合为一个
data.frame
。
- 将未拆分的data.frame设置得较长会节省一些额外的步骤。
#https://stackoverflow.com/questions/58786052/find-variables-that-occur-only-once-across-a-split-data-frame-in-r/58788854#58788854
f <- data.frame(id = c(rep("AA",4),rep("BB",2),rep("CC",2)),X = c(1,2,3,1,4,3),Y = c(99,7,8,6,7))
m <- split(f,f$id) # Here is `m`
unsplit <- do.call(rbind,c(m,make.row.names = F))
molten <- data.frame(unsplit[,drop = F],stack(unsplit[,-1]))
# res <- subset(molten,!duplicated(values) & !duplicated(values,fromLast = T))
res <- molten[as.logical(ave(molten[['values']],molten[['ind']],FUN = function(x) !duplicated(x) & !duplicated(x,fromLast = T))),]
#I would stop here
res
#> id values ind
#> 6 BB 4 X
#> 9 AA 99 Y
#> 11 AA 8 Y
#> 13 BB 6 Y
#to get exact output
res_vector <- res$values
names(res_vector) <- res$ind
split(res_vector,as.character(res$id))
#> $AA
#> Y Y
#> 99 8
#>
#> $BB
#> X Y
#> 4 6
由reprex package(v0.3.0)于2019-11-10创建
这是另一种可能不太复杂的基本方法:
####Way 1 with rapply
vec <- rapply(lapply(m,'[',mods),I)
unique_vec <- vec[!duplicated(vec) & !duplicated(vec,fromLast = T)]
vec_names <- do.call(rbind,strsplit(names(unique_vec),'.',fixed = T))
names(unique_vec) <- substr(vec_names[,2],1) #turns Y1 into Y
split(unique_vec,vec_names[,1])
###Way 2 with data.frame already do.call(rbind,m)
vec <- unlist(
lapply(f[,-1],function(x){
ind <- !duplicated(x) & !duplicated(x,fromLast = T)
ret <- x[ind]
names(ret) <- f[ind,1]
ret
}
)
)
#this is likely overly simplified:
split(vec,sub('.*\\.','',names(vec)))
#this leads to exact result
vec_names <- do.call(rbind,strsplit(names(vec),fixed = T))
names(vec) <- vec_names[,1]
split(vec,2])
$AA
Y Y
99 8
$BB
X Y
4 6
OP在提示中使用table()
出现。 duplicated()
表现出色:
unlist(lapply(f[mods],function(y) names(which(table(y) == 1))))
# X Y1 Y2 Y3
# "4" "6" "8" "99"
vec
#X.BB Y.AA Y.AA Y.BB
# 4 99 8 6
# A tibble: 2 x 13
expression min median `itr/sec` mem_alloc
<bch:expr> <bch> <bch:> <dbl> <bch:byt>
1 table_meth 321us 336us 2794. 10.3KB
2 dup_meth 132us 136us 7105. 31.7KB
bench::mark(
table_meth = {unlist(lapply(f[mods],function(y) names(which(table(y) == 1))))},dup_meth = {
#could get slight performance boost with
#f_id <- f[['id']]
unlist(
lapply(f[,function(x){
ind <- !duplicated(x) & !duplicated(x,fromLast = T)
ret <- x[ind]
names(ret) <- f[ind,1]
#names(ret) <- f_id[ind]
ret
}
)
)},check = F
)
还有data.table中的类似想法:
library(data.table)
molten_dt <- melt(rbindlist(m),id.vars = 'id')
molten_dt[!duplicated(value,by = variable) &
!duplicated(value,by = variable,fromLast = T)]
还有dplyr中的类似想法:
library(dplyr)
library(tidyr)
m%>%
bind_rows()%>%
pivot_longer(cols = -id)%>%
group_by(name)%>%
filter(!duplicated(value) & !duplicated(value,fromLast = T))%>%
group_by(id)%>%
group_split()
,
这不是纯函数式编程,而是基于R的语言:
lapply(split(df,df$id),function(z){
X <- z$X[which(!(z$X %in% df$X[duplicated(df$X)]))]
Y <- z$Y[which(!(z$Y %in% df$Y[duplicated(df$Y)]))]
cbind(X,Y)
}
)
数据:
df <-
structure(list(
id = structure(
c(1L,1L,2L,3L,3L),.Label = c("AA","BB","CC"),class = "factor"
),7)
),class = "data.frame",row.names = c(NA,-8L))
本文链接:https://www.f2er.com/3130305.html