如何在使用R保持原始行顺序的同时按行提取唯一记录和重复记录?

时间:2019-12-11 18:23:37

标签: r dataframe dplyr duplicates edge-list

更新

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

数据框

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的新手,目前正在使用边缘列表形式的协作数据,该边缘列表具有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)和重复记录(AA),但要删除三元组(AA),并且同一行连续出现更多。协作是通过ID分配给发布的,因此顺序应保持不变以便以后进行分析。但是,行内的顺序无关紧要。

所以,最终看起来应该像这样。

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

到目前为止,我已经根据1中的23tuple packagetriplicated尝试了一些方法。

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”例如为国家名称,例如“英格兰”或“中国”。

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

1 个答案:

答案 0 :(得分:2)

我们可以使用unite函数(separatelibrary(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 ),并借助获得所需的输出。

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

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

更新:

感谢@IceCreamToucan的功能:

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
 supportFragmentManager.beginTransaction()
                            .replace(R.id.content_fragment, it1,
                                    "name")
                            .commit()