Слияние векторов строк в списке в R
У меня есть набор строк вместе с соответствующим идентификатором в формате ID: строка в виде списка векторов в R
d <- list( c("SD1:LUSH", "SD44:CANCEL", "SD384:FR563", "SD32:TRUMPET"), c("SD23:SWITCH", "SD1:LUSH", "SD567:TREK"), c("SD42:CRAYON", "SD345:FOX", "SD183:WIRE"), c("SD345:HOLE", "SD340:DUST", "SD387:ROLL"), c("SD455:TOMATO", "SD39:MATURE"), c("SD12:PAINTING", "SD315:MONEY31", "SD387:SPRING"), c("SD32:TRUMPET", "SD1:FIELD"))
[[1]]
[1] "SD1:LUSH" "SD44:CANCEL" "SD384:FR563" "SD32:TRUMPET"
[[2]]
[2] "SD23:SWITCH" "SD1:LUSH" "SD567:TREK"
[[3]]
[3] "SD42:CRAYON" "SD345:FOX" "SD183:WIRE"
[[4]]
[4] "SD345:HOLE" "SD340:DUST" "SD387:ROLL"
[[5]]
[5] "SD455:TOMATO" "SD39:MATURE"
[[6]]
[6] "SD12:PAINTING" "SD315:MONEY31" "SD387:SPRING"
[[7]]
[7] "SD32:TRUMPET" "SD1:FIELD"
Я хотел бы объединить векторы по их идентификаторам. Векторы, имеющие общие идентификаторы, должны быть объединены при сохранении соответствующих строк для формирования нового вектора. Дубликат ID: Строки комбинации могут быть удалены в таких объединенных строках. Всего данных содержит около 2000 таких векторов. Желаемый вывод из данных образца
out <- c("SD1:LUSH, SD1:FIELD, SD23:SWITCH, SD32:TRUMPET, SD44:CANCEL, SD384:FR563, SD567:TREK", "SD12:PAINTING, SD42:CRAYON, SD183:WIRE, SD340:DUST SD345:FOX, SD345:HOLE, SD387:SPRING, SD387:ROLL", "SD455:TOMATO, SD39:MATURE")
[1] "SD1:LUSH, SD1:FIELD, SD23:SWITCH, SD32:TRUMPET, SD44:CANCEL, SD384:FR563, SD567:TREK"
[2] "SD12:PAINTING, SD42:CRAYON, SD183:WIRE, SD315:MONEY31, SD340:DUST SD345:FOX, SD345:HOLE, SD387:SPRING, SD387:ROLL"
[3] "SD455:TOMATO, SD39:MATURE"
Я пытался преобразовать его в data.frame
использовать merge()
, но нашел это бесполезным. Можно ли сначала найти пересечение, используя идентификатор части строки с последующим объединением соответствующих векторов. Я пытался использовать intersect()
а также union()
, но я не могу использовать только часть идентификаторов векторов.
Я довольно новичок в написании R-скриптов.
Обновление Как указал @CarlWitthoft, я пытаюсь сделать условие соответствия для объединения более четким с этим изображением.
Короче говоря, я хочу объединить векторы, которые имеют пересечение между ними в терминах SDxyz:___, или попытаться получить объединение перекрывающихся строковых векторов.
Решил это!!
3 ответа
Создайте блок data.table с одним столбцом с исходными группами, а другой - с разделенными идентификаторами.
d <- list( c("SD1:LUSH", "SD44:CANCEL", "SD384:FR563", "SD32:TRUMPET"), c("SD23:SWITCH", "SD1:LUSH", "SD567:TREK"), c("SD42:CRAYON", "SD345:FOX", "SD183:WIRE"), c("SD345:HOLE", "SD340:DUST", "SD387:ROLL"), c("SD455:TOMATO", "SD39:MATURE"), c("SD12:PAINTING", "SD315:MONEY31", "SD387:SPRING"), c("SD32:TRUMPET", "SD1:FIELD"))
d2 <- lapply(d, function(x) sapply(strsplit(x, ":"), "[", 1))
d <- lapply(d, paste0, collapse=", ")
d2 <- lapply(d2, paste0, collapse=", ")
d <- as.data.frame(as.matrix(lapply(d, paste0, collapse=", ")))
d2 <- as.data.frame(as.matrix(lapply(d2, paste0, collapse=", ")))
d <- as.data.frame(cbind(d,d2))
colnames(d) <- c("sdw", "sd")
d$sd <- as.character(d$sd)
d$sdw <- as.character(d$sdw)
require(data.table)
Bloc <- data.table( d , key = "sd" )
Получить все идентификаторы вместе с соответствующими данными в блоке
Bloc <- Bloc[ , list( ID = unlist( strsplit( sd , "," ) ) ) , by = list(sdw, sd) ]
Bloc$ID <- gsub("^\\s+|\\s+$", "", Bloc$ID)
Bloc <- data.table( Bloc , key = "ID" )
Цикл для объединения векторов с идентификаторами, пересекающимися между ними
Bloc <- as.data.frame(Bloc)
M <- nrow(Bloc)
#create blankd data.frame
G <- data.frame(matrix(ncol=3), stringsAsFactors=FALSE)
G[,1:3] <- as.character(G[,1:3])
#G <- data.frame(sdw=character(), sd=character(), ID= character())
colnames(G) <- c("sdw", "sd", "ID")
N <- M
mch <- as.data.frame(Bloc)
#Loop to sequentially fill data.frame
for (i in 1:M) {
# test if ID already in previous groups
if(Bloc[i,"ID"] %in% G$ID == FALSE) {
# convert element to vector to check for intersect
tm <- strsplit(x=Bloc[i, "sd"], split=", ")
mch$t <- numeric(length=M)
}
for (j in 1:N){
#if intersect exists apply code as 1 mch$t column
ff <- strsplit(x=mch[j, "sd"], split=", ")[[1]]
dd <- intersect (tm[[1]], ff)
if (identical(dd, character(0))== FALSE) mch[j,"t"] = 1
}
submch <- subset(mch, t == 1 )
ID <- submch$ID
Group1 <- sort((unlist(strsplit(paste0(submch$sdw, collapse=","), ","))))
Group1 <- unique(gsub(" ","", Group1))
sdw <- rep(paste0(Group1, collapse=", "), nrow(submch))
Group2 <- sort((unlist(strsplit(paste0(submch$sd, collapse=","), ","))))
Group2 <- unique(gsub(" ","", Group2))
sd <- rep(paste0(Group2, collapse=", "), nrow(submch))
G1 <- cbind(sdw, sd, ID)
G1 <- unique(G1)
G <- rbind(G, G1)
mch$t <- NULL
}
G <- unique(G)
G2 <- data.table(G, key="ID")
G2 <- G2[, list(sdw = paste0(sort(unique(unlist(strsplit(sdw, split=", ")))), collapse=", "),
sd = paste0(sort(unique(unlist(strsplit(sd, split=", ")))), collapse=", ")) , by = "ID"]
G2 <- data.table( G2, key=c("sd", "sdw"))
G2 <- unique(G2)
Получите вывод как data.table
Bloc <- G2[-1,]
Bloc$ID <- NULL
Повторите вышеуказанную петлю, пока не останется больше пересечений
repeat
{
N1 <- nrow(Bloc)
Bloc <- Bloc[ , list( ID = unlist( strsplit( sd , "," ) ) ) , by = list(sdw, sd) ]
Bloc$ID <- gsub("^\\s+|\\s+$", "", Bloc$ID)
Bloc <- data.table( Bloc , key = "ID" )
Bloc <- as.data.frame(Bloc)
M <- nrow(Bloc)
#create blankd data.frame
G <- data.frame(matrix(ncol=3), stringsAsFactors=FALSE)
G[,1:3] <- as.character(G[,1:3])
#G <- data.frame(sdw=character(), sd=character(), ID= character())
colnames(G) <- c("sdw", "sd", "ID")
N <- M
mch <- as.data.frame(Bloc)
#Loop to sequentially fill data.frame
for (i in 1:M) {
# test if ID already in previous groups
if(Bloc[i,"ID"] %in% G$ID == FALSE) {
# convert element to vector to check for intersect
tm <- strsplit(x=Bloc[i, "sd"], split=", ")
mch$t <- numeric(length=M)
}
for (j in 1:N){
#check if intersect exists and code accordingly
ff <- strsplit(x=mch[j, "sd"], split=", ")[[1]]
dd <- intersect (tm[[1]], ff)
if (identical(dd, character(0))== FALSE) mch[j,"t"] = 1
}
submch <- subset(mch, t == 1 )
ID <- submch$ID
Group1 <- sort((unlist(strsplit(paste0(submch$sdw, collapse=","), ","))))
Group1 <- unique(gsub(" ","", Group1))
sdw <- rep(paste0(Group1, collapse=", "), nrow(submch))
Group2 <- sort((unlist(strsplit(paste0(submch$sd, collapse=","), ","))))
Group2 <- unique(gsub(" ","", Group2))
sd <- rep(paste0(Group2, collapse=", "), nrow(submch))
G1 <- cbind(sdw, sd, ID)
G1 <- unique(G1)
G <- rbind(G, G1)
mch$t <- NULL
}
G <- unique(G)
G2 <- data.table(G, key="ID")
G2 <- G2[, list(sdw = paste0(sort(unique(unlist(strsplit(sdw, split=", ")))), collapse=", "),
sd = paste0(sort(unique(unlist(strsplit(sd, split=", ")))), collapse=", ")) , by = "ID"]
G2 <- data.table( G2, key=c("sd", "sdw"))
G2 <- unique(G2)
Bloc <- G2[-1,]
Bloc$ID <- NULL
N2 <- nrow(Bloc)
if (N1 == N2)
break
}
Выход
Блок $ SDW
[1] "SD1:FIELD, SD1:LUSH, SD23:SWITCH, SD32:TRUMPET, SD384:FR563, SD44:CANCEL, SD567:TREK"
[2] "SD12:PAINTING, SD183:WIRE, SD315:MONEY31, SD340:DUST, SD345:FOX, SD345:HOLE, SD387:ROLL, SD387:SPRING, SD42:CRAYON"
[3] "SD39:MATURE, SD455:TOMATO"
Вы можете попробовать что-то вроде:
id <- lapply(d, function(x) sapply(strsplit(x, ":"), "[", 1))
tbl <- table(unlist(id))
выделить идентификаторы и найти, какие из них встречаются в нескольких записях:
repeatIDs <- names(tbl)[tbl>1]
out <- list()
Теперь создайте сжатый список любого, который содержит дублированные идентификаторы с:
for (i in repeatIDs) {
ind <- sapply(id, function(x) any(i==x))
out[[i]] <- paste(unlist(d[ind]), collapse=", ")
}
Я думаю, что если вы рассчитываете id
в ответ Гэвина, а затем рассчитать все intersect(id[[j]],id[[k]])
или, может быть, даже лучше:
for (j in unique(unlist(id))) sapply(id,function(k) j%in%k)
даст вам пересечения (вам придется массировать TRUE TRUE FALSE...
векторы, которые вытекают из этого кода)
РЕДАКТИРОВАТЬ: так вот что для продолжения:
id <- lapply(sdin, function(x) sapply(strsplit(x, ":"), "[", 1))
# id is
# [[1]]
# [1] "SD1" "SD44" "SD384" "SD32"
# [[2]]
# [1] "SD23" "SD1" "SD567"
# [[3]]
# [1] "SD42" "SD345" "SD183"
# [[4]]
# [1] "SD345" "SD340" "SD387"
# [[5]]
# [1] "SD455" "SD39"
# [[6]]
# [1] "SD12" "SD315" "SD387"
# [[7]]
# [1] "SD32" "SD1"
idnames<-unique(unlist(id))
# [1] "SD1" "SD44" "SD384" "SD32" "SD23" "SD567" "SD42"
# [8] "SD345" "SD183" "SD340" "SD387" "SD455" "SD39" "SD12"
# [15] "SD315"
matid<-matrix(NA,nrow=15,ncol=7)
for(k in 1:length(idnames) ) matid[k,] <- unlist(sapply(id, function(j) idnames[k]%in%j))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] TRUE TRUE FALSE FALSE FALSE FALSE TRUE
# [2,] TRUE FALSE FALSE FALSE FALSE FALSE FALSE
# [3,] TRUE FALSE FALSE FALSE FALSE FALSE FALSE
# [4,] TRUE FALSE FALSE FALSE FALSE FALSE TRUE
# [5,] FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# [6,] FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# [7,] FALSE FALSE TRUE FALSE FALSE FALSE FALSE
# [8,] FALSE FALSE TRUE TRUE FALSE FALSE FALSE
# [9,] FALSE FALSE TRUE FALSE FALSE FALSE FALSE
# [10,] FALSE FALSE FALSE TRUE FALSE FALSE FALSE
# [11,] FALSE FALSE FALSE TRUE FALSE TRUE FALSE
# [12,] FALSE FALSE FALSE FALSE TRUE FALSE FALSE
# [13,] FALSE FALSE FALSE FALSE TRUE FALSE FALSE
# [14,] FALSE FALSE FALSE FALSE FALSE TRUE FALSE
# [15,] FALSE FALSE FALSE FALSE FALSE TRUE FALSE
Каждая строка этой матрицы соответствует одному из значений "SDx", а каждый столбец - одному из элементов списка в ваших входных данных. d
список. Вы должны быть в состоянии генерировать свои диаграммы Венни из этой таблицы.