【问题标题】:How to extract unique and double records by row while keeping original row order using R?如何在使用 R 保持原始行顺序的同时按行提取唯一和双记录?
【发布时间】:2019-12-11 18:23:37
【问题描述】:

原始(见下面的更新)

我是 R 的新手,目前正在处理具有 32 列和大约 200.000 行的边缘列表形式的协作数据,如下所示:

1  A    A    A    B    C    A
2  A    B    B    B    C    A
3  A    B    C    C    C    C
4  B    A    B    A    B    C

A、B、C 代表参与出版物的研究机构所在的国家/地区。 在真实数据集中,“A”是例如国家名称,例如“英格兰”或“中国”。

我想保留唯一记录 (A) 和双记录 (A A),但删除三元组 (A A A) 和更多连续出现的同一记录。协作按 ID 分配给出版物,因此顺序应保持不变,以便以后进行分析。但是,行内的顺序并不重要。

所以,它最终应该是这样的。

1  A   A    B    C    
2  A   B    B    C    A
3  A   B    C    C        
4  B   A    B    A    C

到目前为止,我已经基于123triplicatedtuple package 尝试了一些东西。

df <- data.frame(CTR1 = c("A", "A", "A", "B"), CTR2 = c("A", "B", "B", "A"), CTR3 = c("A", "B", "B", "A"), CTR4 = c("B", "B", "C", "A"), CTR5 = c("C", "C", "C", "B"), CTR6 = c("A", "A", "C", "C"), ID = c(1,2,3,4))

# remember the ID

n <-df$ID

# transpose df (data frame)

dt <- as.data.frame(t(df[, -1]))
colnames(dt) <- n

library(tuple)

dt[!(triplicated(dt) | triplicated(dt, fromLast= TRUE)), ]

# Create new transposed variable

df2 <- as.data.frame(t(df))

但是,我使用 dt[!(triplicated(dt) | triplicated(dt, fromLast= TRUE)), ] 删除了完整的行,而不是仅删除逐行显示盈余的特定记录,这导致我进入以下 4x4 表...

   CTR1 CTR3 CTR4 CTR5                   CTR1 CTR2 CTR3 CTR4 CTR5 CTR6
1  A    A    B    C                   1  A    A    B    C        
2  A    B    B    C    rather than    2  A    B    B    C    A   
3  A    B    C    C                   3  A    B    C    C        
4  B    A    A    B                   4  B    A    B    A    C    

我还查看了 dplyr 以及回复 herehere,但到目前为止还没有找到合适的方法。

原始问题描述的工作解决方案

library(tidyr)
library(dplyr)

countrydf %>% 
  unite(concat,CTR1:CTR6, sep = "") %>% 
  mutate(concat = gsub("([a-zA-Z1-9])\\1{2,}", "\\1\\1-", concat)) %>% 
  separate(concat, paste0("CTR", 1:6), sep = "(?<=.)", remove = TRUE)

Edit1:为澄清而调整的描述:在真实数据集中,“A”是例如国家名称,例如“England”或“China”。

Edit2:添加更准确的可重现示例。

更新

添加了一个更准确的可重现示例,并为原始问题描述合并了正确答案(见下文):

countrydf <- data.frame(ID = c(1,2,3,4), 
CTR1 = c("England", "England", "England", "China"),
CTR2 = c("England", "China", "China", "England"),
CTR3 = c("England", "China", "China", "England"),
CTR4 = c("China", "China", "USA", "England"),
CTR5 = c("USA", "USA", "USA", "China"),
CTR6 = c("England", "England", "USA", "USA"))

期望的结果

     CTR1    CTR2    CTR3   CTR4  CTR5  CTR6      ID
1    England England        China USA              1
2    England China   China        USA   England    2
3    England China   China  USA   USA              3
4    China   England England      China USA        4

【问题讨论】:

    标签: r dataframe dplyr duplicates edge-list


    【解决方案1】:

    我们可以使用tidyr 函数(uniteseparate)并在 的帮助下实现所需的输出。

    这应该非常接近您的需要。

    library(tidyr)
    library(dplyr)
    
    df1 %>% 
      unite(concat,CTR1:CTR6, sep = "") %>% 
      mutate(concat = gsub("([a-zA-Z1-9])\\1{2,}", "\\1\\1-", concat)) %>% 
      separate(concat, paste0("CTR", 1:6), sep = "(?<=.)", remove = TRUE)
    
    #>   ID CTR1 CTR2 CTR3 CTR4 CTR5 CTR6
    #> 1  1    A    A    -    B    C    A
    #> 2  2    A    B    B    -    C    A
    #> 3  3    A    B    B    C    C    -
    #> 4  4    B    A    A    -    B    C
    

    更新:

    感谢@IceCreamToucan的功能:

    library(tidyr)
    library(dplyr)
    
    ICT_fn <- function(x){
    xsplit <- strsplit(x, '')[[1]]
    xsplit[data.table::rowid(xsplit) >= 3] <- '-'
    paste(xsplit, collapse = '')}
    
    df1 %>% 
      unite(concat,CTR1:CTR6, sep = "") %>% 
      rowwise() %>% 
      mutate(concat = ICT_fn(concat)) %>% 
      separate(concat, paste0("CTR", 1:6), sep = "(?<=.)", remove = TRUE)
    
    #> # A tibble: 4 x 7
    #>      ID CTR1  CTR2  CTR3  CTR4  CTR5  CTR6 
    #>   <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
    #> 1     1 A     A     -     B     C     -    
    #> 2     2 A     B     B     -     C     A    
    #> 3     3 A     B     B     C     C     -    
    #> 4     4 B     A     A     -     B     C
    

    这个更新后的解决方案,经过最少的调整,也适用于国家名称;往下看:

    df2 <- data.frame(ID = c(1,2,3,4),
                             CTR1 = c("England", "England", "England", "France"), 
                             CTR2 = c("England", "France", "France", "England"), 
                             CTR3 = c("England", "France", "France", "England"), 
                             CTR4 = c("France", "France", "Germany", "England"),
                             CTR5 = c("Germany", "Germany", "Germany", "France"), 
                             CTR6 = c("England", "England", "Germany", "Germany"))
    
    library(tidyr)
    library(dplyr)
    
    ICT_fn <- function(x){ #Credits to IceCreamToucan
      xsplit <- strsplit(x, ',')[[1]]
      xsplit[data.table::rowid(xsplit) >= 3] <- '-'
      paste(xsplit, collapse = ',')}
    
    df2 %>% 
      unite(concat,CTR1:CTR6, sep = ",") %>% 
      rowwise() %>% 
      mutate(concat = ICT_fn(concat)) %>% 
      separate(concat, paste0("CTR", 1:6), sep = ",", remove = TRUE)
    
    #> # A tibble: 4 x 7
    #>      ID CTR1    CTR2    CTR3    CTR4    CTR5    CTR6   
    #>   <dbl> <chr>   <chr>   <chr>   <chr>   <chr>   <chr>  
    #> 1     1 England England -       France  Germany -      
    #> 2     2 England France  France  -       Germany England
    #> 3     3 England France  France  Germany Germany -      
    #> 4     4 France  England England -       France  Germany
    

    【讨论】:

    • 谢谢!它在这个例子中工作得很好,但我在翻译真实数据集时有点挣扎。它看起来像这样:ID V1 V2 V3 V4 V5 V6 V7 V81 E N G L A N D -2 K U W A I T - - 所以,它基本上将每个字母分成一个单元格。如果我自己找不到,我会回来找你的。
    • 好的,我意识到我的描述有点不对劲。 “A”在真实数据集中,例如像“英格兰”这样的国家。因此,主要关注点与mutate(concat = gsub("([a-zA-Z1-9])\\1{2,}", "\\1\\1-", concat)) 和正则表达式有关。我刚刚回复以澄清我的问题,但仍在尝试获得适当的解决方案。
    猜你喜欢
    • 2020-05-25
    • 2013-07-26
    • 1970-01-01
    • 2019-05-02
    • 2020-04-05
    • 2016-10-26
    • 1970-01-01
    相关资源
    最近更新 更多