【问题标题】:Collapse and intersect data frames折叠和交叉数据框
【发布时间】:2016-12-22 11:09:21
【问题描述】:

我有两个 data.frames,它们有 3 列: 1. id - 唯一键

  1. target - 分号分隔的唯一值

  2. source - 每个数据帧都相似,但两个 data.frames 不同。

这是模拟数据:

set.seed(1)
df.1 <- data.frame(id=LETTERS[sample(length(LETTERS),10,replace=F)],
                   target=sapply(1:10,function(x) paste(LETTERS[sample(length(LETTERS),5,replace=F)],collapse=";")),
                   source="A",stringsAsFactors=F)

df.2 <- data.frame(id=LETTERS[sample(length(LETTERS),5,replace=F)],
                   target=sapply(1:5,function(x) paste(LETTERS[sample(length(LETTERS),5,replace=F)],collapse=";")),
                   source="B",stringsAsFactors=F)

我正在寻找一个可以将两个 data.frames 折叠在一起并创建 3 列的函数:

1.intersected.targets - 分号分隔的唯一值,它们在两个 data.frames 之间相交

2.source1.targets - 第一个 data.frame 独有的目标

3.source2.targets - 第二个data.frame独有的目标

因此,对于上面的示例,生成的 data.frame 将是:

> res.df
   id intersected.targets sourceA.targets sourceB.targets
1   G                  NA       F;E;Q;I;X            <NA>
2   J                  NA       M;R;X;I;Y            <NA>
3   N                  NA       Y;F;P;C;Z            <NA>
4   U                  NA       K;A;J;U;H            <NA>
5   E                  NA       M;O;L;E;S            <NA>
6   S                  NA       R;T;C;Q;J            <NA>
7   W                  NA       V;Q;S;M;L            <NA>
8   M                  NA       U;A;L;Q;P            <NA>
9   B                  NA       C;H;M;P;I            <NA>
10  X                  NA            <NA>       G;L;S;B;T
11  H                  NA            <NA>       I;U;Z;H;K
12  Y                  NA            <NA>       L;R;J;H;Q
13  O                  NA            <NA>       F;R;C;Z;D
14  L                  V       M;K;F;B       X;J;R;Y

【问题讨论】:

  • 您可以从library(data.table) ; dcast(rbind(setDT(df.1), setDT(df.2)), id ~ source, value.var = "target") 开始。不确定您在 intersected.targets 列中想要什么,因为您没有在所需的输出中指定它
  • 你不需要这个修改(更不用说你的代码不起作用),因为你已经有一个通用的“V”了
  • 对,对不起。相应地编辑
  • 我猜@DavidArenburg 只是暂时删除了他的回复并正在对其进行编辑,如果是这种情况,我将建议他继续使用数据表方法,使用转换来列出源列的列和然后运行setdiff, by=id。
  • @42- 不,我没有时间,如果有任何解决方案,您可以发布。

标签: r dataframe collapse aggregates


【解决方案1】:

这是 DavidArenberg 已删除答案的延续,它教会了我在 data.table 中创建列表列的概念。我不知道如何正确实现我逐行使用setdiff 的想法,但最终在多次搜索后找到了 Frank 的答案。这是大卫的(部分)答案:

===== 这是针对具有多个交叉点且单个交叉点中有多个字母的不同种子的可能解决方案

#Generating Data

set.seed(123)
df.1 <- data.frame(id=LETTERS[sample(length(LETTERS),10,replace=F)],
                   target=sapply(1:10,function(x) paste(LETTERS[sample(length(LETTERS),5,
                                                                replace=F)],collapse=";")),
                   source="A",stringsAsFactors=F)

df.2 <- data.frame(id=LETTERS[sample(length(LETTERS),5, replace=F)],
                   target=sapply(1:5,function(x) paste(LETTERS[sample(length(LETTERS),5, 
                                                               replace=F)],collapse=";")),
                   source="B",stringsAsFactors=F)
#Solution

library(data.table) 
library(stringi)
res <- dcast(rbind(setDT(df.1), setDT(df.2)), id ~ source, value.var = "target")
res[!is.na(A) & !is.na(B), intersected.targets := 
                             stri_extract_all(A, regex = gsub(";", "|", B, fixed = TRUE))]
res

===========================

所以我使用他的列表代码制作了一个 A2 和 B2 列,它们是 A 和 B 的列表版本

res[ , A2 := stri_extract_all(A, regex = "[[:alpha:]]") ]
 res[ , B2 := stri_extract_all(B, regex = "[[:alpha:]]") ]

然后用Map()逐行做setdiff:

res[, SourceA := Map( setdiff, A2, intersected.targets)]
res[, SourceB := Map( setdiff, B, intersected.targets)]
 res
#-------------------------------
    id         A         B intersected.targets        A2        B2   SourceA   SourceB
 1:  A M;S;F;H;X        NA                NULL M,S,F,H,X        NA M,S,F,H,X        NA
 2:  C        NA T;P;R;A;K                NULL        NA T,P,R,A,K        NA T,P,R,A,K
 3:  G        NA G;Q;K;S;C                NULL        NA G,Q,K,S,C        NA G,Q,K,S,C
 4:  H Y;L;Q;N;C        NA                NULL Y,L,Q,N,C        NA Y,L,Q,N,C        NA
 5:  J X;R;P;W;O F;J;O;I;C                   O X,R,P,W,O F,J,O,I,C   X,R,P,W   F,J,I,C
 6:  K D;K;J;I;Z        NA                NULL D,K,J,I,Z        NA D,K,J,I,Z        NA
 7:  Q D;F;L;G;S        NA                NULL D,F,L,G,S        NA D,F,L,G,S        NA
 8:  R        NA L;U;T;S;J                NULL        NA L,U,T,S,J        NA L,U,T,S,J
 9:  T X;G;B;H;U        NA                NULL X,G,B,H,U        NA X,G,B,H,U        NA
10:  U S;N;O;G;D        NA                NULL S,N,O,G,D        NA S,N,O,G,D        NA
11:  W Z;W;Q;S;A        NA                NULL Z,W,Q,S,A        NA Z,W,Q,S,A        NA
12:  X B;L;T;C;M        NA                NULL B,L,T,C,M        NA B,L,T,C,M        NA
13:  Z F;D;S;U;I L;Y;V;U;D                 D,U F,D,S,U,I L,Y,V,U,D     F,S,I     L,Y,V

我将把清理工作留作学生练习。

【讨论】:

    【解决方案2】:

    正如@42- 所提到的,这种类型的数据清理的痛点在于取消列出列表的数据框。

    library(dplyr)
    library(stringr)
    df <- full_join(df.1, df.2) %>% 
      spread(source, target)  %>%
      mutate(intersect_targets = str_c(A,B,sep = ";"))
    
    df[,4][!is.na(df[,4])] <- names(do.call("c",lapply(df$intersect_targets, function(x) 
    which(table(str_split(x, ";"))>1))))
    
    a <- sapply(seq(nrow(df)), function(x) {
    str_split(df[x,2:3],";")
    })
    
    sa <-  do.call("c",lapply(mapply(setdiff,a[1,], a[2,]),paste0, collapse = ","))
    sb <- do.call("c",lapply(mapply(setdiff,a[2,], a[1,]), paste0, collapse = ","))
    
    df[,2:3] <-cbind(sa,sb)
    
     head(df)
      id         A         B intersect_targets
    1  B C,H,M,P,I        NA              <NA>
    2  E M,O,L,E,S        NA              <NA>
    3  G F,E,Q,I,X        NA              <NA>
    4  H        NA I,U,Z,H,K              <NA>
    5  J M,R,X,I,Y        NA              <NA>
    6  L   M,K,F,B   X,J,R,Y                 V
    

    【讨论】:

    • 您似乎没有从输入集中删除相交元素。
    • 我们可以在非列表版本上使用类似:A &lt;- gsub( paste( ";*, intersect_targets), "", A)。在@AM 上花一个小时讨论一个问题,却得不到任何人的支持,这有点令人沮丧,嗯?
    • 你有我的。直到现在才有机会从头到尾读完。
    猜你喜欢
    • 2021-09-10
    • 2018-06-22
    • 2013-12-13
    • 1970-01-01
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    相关资源
    最近更新 更多