如何上下移动字符串并从中删除类似的字符串?

时间:2016-06-27 11:28:04

标签: r

我问了一个可能不太清楚的问题。所以我试着以一种可以理解的方式解释它。这是我的数据

我的数据看起来像这样

看起来像这样

#             V1      V2               V3
#1                 Q9UNZ5             Q9Y2W1
#2 Q9ULV4;Q6QEF8                     
#3                                    Q9UNZ5
#4                  Q9H6F5              
#5                  Q9H2K0     Q9ULV4;Q6QEF8
#6                  Q9GZZ1            Q9UKD2
#7        Q9H6F5    Q9GZZ1            Q9GZZ1
#8        Q9GZZ1                      Q9NYF8
#9        Q9BWS9                     

我想在所有这些字符串中删除重复的字符串 例如,V1我们第一次拥有所有字符串,所以我们不会删除任何东西只是安排它们

Q9ULV4
Q6QEF8
Q9H6F5
Q9GZZ1 
Q9BWS9

然后我们用第一列检查第二列字符串,然后删除重复的那些字符串并再次排列它们。对于第三列,我们检查第一列和第二列的字符串,如果相似,则我们删除然后排列它们。所以输出应该如下所示。

Q9ULV4  Q9UNZ5  Q9Y2W1
Q6QEF8  Q9H2K0  Q9UKD2
Q9H6F5          Q9NYF8
Q9GZZ1          
Q9BWS9          

这与我提出的任何问题都不相似;所以,如果仍然不清楚,请评论,我试着解释一下

4 个答案:

答案 0 :(得分:5)

我会分两步来处理这个问题:

1)每列获取唯一元素并转换为列表:

l <- lapply(df, function(x) unique(unlist(strsplit(as.character(x), ";"))))

2)删除任何先前列中出现的重复项

for(i in seq_along(l)) {
  l[[i]] <- setdiff(l[[i]], unlist(l[seq_len(i-1L)]))
}

我使用list而不是data.frame的原因是因为data.frame要求所有列都具有相同的行数,这不是这里的情况(除非你用NA或空字符串填充它们。在这种情况下,list结构是可行的方法。

答案 1 :(得分:4)

第一行将df转换为列表L。第二行创建一个长格式数据框long,其中包含column1中的值和第2列中的df列名称作为因子。需要将其作为一个因素,因为级别保留所有列名称,包括由于仅包含重复项而随后被删除的列名称。此外,它保留列名称的顺序。最后一行删除了生成long0的重复项。没有包使用。

L <- lapply(df,  function(x) unlist(strsplit(as.character(x), ";")))
long <- transform(stack(L), ind = factor(as.character(ind), levels = names(df)))
long0 <- subset(long, !duplicated(values))

现在我们考虑三种可能的输出形式:

1)长格式数据框

> long0
   values ind
1  Q9ULV4  V1
2  Q6QEF8  V1
3  Q9H6F5  V1
4  Q9GZZ1  V1
5  Q9BWS9  V1
6  Q9UNZ5  V2
8  Q9H2K0  V2
11 Q9Y2W1  V3
15 Q9UKD2  V3
17 Q9NYF8  V3

2)列表

L0 <- unstack(long0)

,并提供:

> L0
$V1
[1] "Q9ULV4" "Q6QEF8" "Q9H6F5" "Q9GZZ1" "Q9BWS9"

$V2
[1] "Q9UNZ5" "Q9H2K0"

$V3
[1] "Q9Y2W1" "Q9UKD2" "Q9NYF8"

3)字符矩阵创建L0版本,用NA替换每个零长度组件,然后将每个组件的长度扩展为最大长度,重新变为矩阵同时通过sapply

lens <- lengths(L0)
m0 <- sapply(replace(L0, !lens, NA), "length<-", max(lens))

,并提供:

> m0
     V1       V2       V3      
[1,] "Q9ULV4" "Q9UNZ5" "Q9Y2W1"
[2,] "Q6QEF8" "Q9H2K0" "Q9UKD2"
[3,] "Q9H6F5" NA       "Q9NYF8"
[4,] "Q9GZZ1" NA       NA      
[5,] "Q9BWS9" NA       NA     

更新:一些修复和澄清。

注1:可重复形式的输入df为:

df <-
structure(list(V1 = c("", "Q9ULV4;Q6QEF8", "", "", "", "", "Q9H6F5", 
"Q9GZZ1", "Q9BWS9"), V2 = c("Q9UNZ5", "", "", "Q9H6F5", "Q9H2K0", 
"Q9GZZ1", "Q9GZZ1", "", ""), V3 = c("Q9Y2W1", "", "Q9UNZ5", "", 
"Q9ULV4;Q6QEF8", "Q9UKD2", "Q9GZZ1", "Q9NYF8", "")), .Names = c("V1", 
"V2", "V3"), row.names = c(NA, -9L), class = "data.frame")

注2:在R的最新开发版本中,&#34; R正在开发(不稳定)(2016-07-05 r70861)&#34;,{{1}顶部附近的行可以简化为long <-,因为long <- stack(L)会为该版本的R中的所有级别创建一个因子。

答案 2 :(得分:2)

我会以这种方式基于duplicate函数在普通R中执行此操作:

lst <- lapply(df, function(x) unlist(strsplit(as.character(x), ";", fixed = TRUE)))
cols <- colnames(df)
seen_entries <- NULL

for (i in (1:ncol(df))) { 
  n_seen_before <- length(seen_entries)
  seen_entries <- c(seen_entries, lst[[cols[i]]])
  lst[[cols[i]]] <- lst[[cols[i]]][(!duplicated(seen_entries))[
                                        (n_seen_before+1):length(seen_entries)]]
}

输出是:

> lst
$V1
[1] "Q9ULV4" "Q6QEF8" "Q9H6F5" "Q9GZZ1" "Q9BWS9"

$V2
[1] "Q9UNZ5" "Q9H2K0"

$V3
[1] "Q9Y2W1" "Q9UKD2" "Q9NYF8"

可能有更优雅的解决方案使用例如data.table或类似的东西。

答案 3 :(得分:2)

我们可以尝试

lst <- lapply(df, function(x) unique(unlist(strsplit(as.character(x), ";"))))
lapply(seq_along(lst), function(i) {
            v1 <- unlist(lst[seq(i)])
            setdiff(lst[[i]], v1[duplicated(v1)])})
#[[1]]
#[1] "Q9ULV4" "Q6QEF8" "Q9H6F5" "Q9GZZ1" "Q9BWS9"

#[[2]]
#[1] "Q9UNZ5" "Q9H2K0"

#[[3]]
#[1] "Q9Y2W1" "Q9UKD2" "Q9NYF8"