【问题标题】:Combine data frames picking only columns sharing same name beginnings across data frames合并数据框,仅选择跨数据框共享相同名称开头的列
【发布时间】:2018-09-23 00:16:42
【问题描述】:

我有这两个数据框,我想用它们来创建另一个:

df<-as.data.frame(matrix(rexp(200, rate=.1), ncol=10))
colnames(df)<-c("one","two","three","four","five","six","seven","eight","nine","ten")
df


    df.new<-as.data.frame(matrix(rexp(155, rate=.1), ncol=8))
colnames(df.new)<-c("one.two","one.two.new","three.two","three.two.new","five.one","five.one.new","seven.two","seven.two.new")
df.new

我的想法是有一个包含这些列的数据框:

(one|one.two|one.two.new|three|three.two|three.two.new|five|five.one|five.one.new)

我可以手动完成,但我的数据框比这些大得多。

dplyr 包可以做到这一点吗?

【问题讨论】:

  • dfdf.new 的观察次数不同。你想如何合并它们?
  • 还是一样:df 有 20 个观测值,而 df.new 有 25 个观测值。您想用 NA 填充缺失值吗?
  • 我建议您仔细阅读 reshape2 / tidyr 文档。然后在熔化和铸造之间使用 rbind 。还可以考虑改写标题,因为它写得非常宽泛。
  • 并非 df 中的所有列都在结果中。这是故意的吗?此外,列名 Five.one 和 Five.one.new 不符合命名模式 one.two、one.two.new 等。
  • @ANG 我又编辑了。

标签: r dplyr


【解决方案1】:

这是另一个较短的选择。我只是不喜欢宽桌​​子……所以无论如何你都得把它融化。

to.pick <- unique(unlist(sapply(colnames(df.new), function(x) {
  Reduce(function(a,b) paste(a, b, sep="."), strsplit(x, '.', fixed=TRUE)[[1]], accumulate=TRUE)
})))
zz <- cbind(df, df.new)
out <- subset(zz, select=to.pick)
colnames(out)
 [1] "one"           "one.two"       "one.two.new"   "three"         "three.two"     "three.two.new" "five"         
 [8] "five.one"      "five.one.new"  "seven"         "seven.two"     "seven.two.new"

原答案

对按列名部分过滤的数据使用熔化/铸造。

library(tidyr)

将内容传播到“正常”的长表示中

df$idx <- 1:nrow(df)
gdf <- gather(df, key, value, -idx)
df.new$idx <- 1:nrow(df.new)
gdf.new <- gather(df.new, key, value, -idx)

获取独特的第一部分

uu <- unique(gdf.new$key)
to.pick <- sapply(uu, function(x) {
  strsplit(x, '.', fixed=TRUE)[[1]][1]
  })

仅对我们想要的第一个数据帧中的那些进行子集。

gdf.ss <- subset(gdf, key %in% to.pick)

合并仍为“正常”长格式的数据。

out <- rbind(gdf.ss, gdf.new)

改成“丑陋”的宽幅格式

out.wide <- spread(out, key, value)
colnames(out.wide)
 [1] "idx"           "five"          "five.one"     
 [4] "five.one.new"  "one"           "one.two"      
 [7] "one.two.new"   "seven"         "seven.two"    
[10] "seven.two.new" "three"         "three.two"    
[13] "three.two.new"

如果您坚持不严格按字母顺序排序的列,我会更新我的答案。

【讨论】:

    【解决方案2】:

    列分为三组,设 N= 为簇的数量。

     N=3 # for the example provided
     foo=seq(1,2*N+1,2) 
     dplyr::bind_cols(df, df.new) %>% dplyr::select(names(.)[c(foo, 
     foo+10, foo+11)]) 
    

    【讨论】:

    • 谢谢@rgt47。几乎是这样,因为我的数据框要大得多,我将不得不通过列的名称来识别。识别第二个数据帧上的“一个”,然后他将转到第一个数据帧并包含该列。
    • 您的解决方案无法扩展!
    • @rgt47 one.two.new.newer 怎么样?
    猜你喜欢
    • 2021-12-17
    • 2018-09-01
    • 1970-01-01
    • 2019-12-24
    • 2013-05-09
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    • 2021-02-18
    相关资源
    最近更新 更多