【问题标题】:How can I combine pairs of variables using suffixes in R?如何使用 R 中的后缀组合变量对?
【发布时间】:2019-09-19 06:18:18
【问题描述】:

我有一个非常宽的数据集(1,000 多列),其中大约 160 个是以下格式的对:Var1.r 和 Var1.s; Var2.r 和 Var2.s 等等。

下面是一个小例子,说明数据现在的样子:

df <- tibble(Var1.r=c("Apple", "Pear", NA), Var1.s = c(NA, NA, "Dog"), 
             Var2.r = c("Boat", NA, NA), Var2.s = c(NA, "Platypus", NA),
             AnotherVar = c(1,2,3))

# A tibble: 3 x 5
  Var1.r Var1.s Var2.r Var2.s   AnotherVar
  <chr>  <chr>  <chr>  <chr>         <dbl>
1 Apple  NA     Boat   NA                1
2 Pear   NA     NA     Platypus          2
3 NA     Dog    NA     NA                3

我希望它看起来像什么:

> df2
# A tibble: 3 x 3
  Var1  Var2     AnotherVar
  <chr> <chr>         <dbl>
1 Apple Boat              1
2 Pear  Platypus          2
3 Dog   NA                3

我编写了一个函数来合并每对列merge_columns,它以两列作为参数并返回所需的合并列。通常我会这样做:

df2 <- df %>% 
  mutate(Var1 = merge_cols(Var1.r, Var1.s),
         Var2 = merge_cols(Var2.r, Var2.s))

然后删除所有 .r 和 .s 列。除了我不想把同一行写 80 次。

一定有更好的办法吧?

更新:我最终选择了一个丑陋但可行的解决方案。

# select all the ".s" columns 
# (which will always have their .r counterparts)
to_merge <- df %>% select(ends_with(".s")) %>% names()

S <- NA
# loop through all the .s column names
for (S in to_merge) { 
  R <- gsub('(.+).s', '\\1.r', S) #create the equivalent .r col name
  # merge them using merge_cols() and save them to the .r column 
  df[R] <- merge_cols(df[[S]],df[[R]])
}

# drop all the .s columns
df <- df %>% select(-ends_with(".s"))
# rename the variables that end in .r to be the "main" variable
names(df) <- gsub('(.+).r$', '\\1', names(df))

它超级难看,但它比重塑数据框工作得更快(因为我有太多列但没有那么多行),并且允许我根据我想要合并数据的方式使用自定义 merge_cols 函数。

【问题讨论】:

标签: r


【解决方案1】:

您应该能够通过将数据框转换为长格式,然后解析列名,然后删除缺失值来做到这一点。例如:

library(dplyr)
library(tidyr)

df <-
  tibble(
    Var1.r = c("Apple", "Pear", NA),
    Var1.s = c(NA, NA, "Dog"),
    Var2.r = c("Boat", NA, NA),
    Var2.s = c(NA, "Platypus", NA),
    AnotherVar = c(1, 2, 3)
  )

df %>% gather(Var, Val, -AnotherVar) %>% 
  separate(Var, into=c("Name", "Suffix"), sep="\\.") %>% 
  drop_na(Val) %>% 
  select(-Suffix) %>% 
  spread(Name, Val)

# A tibble: 3 x 3
  AnotherVar Var1  Var2    
       <dbl> <chr> <chr>   
1          1 Apple Boat    
2          2 Pear  Platypus
3          3 Dog   NA   

或者更笼统一点,假设它们都以Var 开头,则使用starts_with 捕获您想要gather 的变量:

df <-
  tibble(
    Var1.r = c("Apple", "Pear", NA),
    Var1.s = c(NA, NA, "Dog"),
    Var2.r = c("Boat", NA, NA),
    Var2.s = c(NA, "Platypus", NA),
    AnotherVar = c(1, 2, 3),
    AnotherVar2 = c("a", NA, "c"),
    AnotherVar3 = c("a1", "b2", NA)
  )

df %>% gather(Var, Val, starts_with("Var")) %>% 
  separate(Var, into=c("Name", "Suffix"), sep="\\.") %>% 
  drop_na(Val) %>% 
  select(-Suffix) %>% 
  spread(Name, Val)

# A tibble: 3 x 5
  AnotherVar AnotherVar2 AnotherVar3 Var1  Var2    
       <dbl> <chr>       <chr>       <chr> <chr>   
1          1 a           a1          Apple Boat    
2          2 NA          b2          Pear  Platypus
3          3 c           NA          Dog   NA 

【讨论】:

  • 谢谢。我尝试了这个解决方案,但我的实际数据有大约 80 对需要合并的变量(对于数据的不同部分,这将发生多次)和数千列。在该过程结束时,我遗漏了 10 个观察结果,并且我无法直观地检查每个步骤之间的数据框以找出我哪里出错了。
  • 没有真实数据很难解决这个问题。 drop_na 可能没有捕获某些情况。如果您的 merge_cols 函数更健壮并且如果您知道所有列的名称,则可以尝试在所有列对上使用 lapplypurrr::map 函数。特别是,purrr::map2_dfc 可能在此处用于循环两个列名向量,应用函数 merge_cols 并返回一个列旁 data.frame
  • 非常感谢您的帮助!我认为问题在于,一些观察结果只有所有变量的 NA,所以它们最终被丢弃了。抱歉,我无法更好地描述我的问题,但这些技巧最终对其他东西有用。最后,一个很好的老式 for 循环解决了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-10
  • 2017-03-19
  • 2019-06-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多