按顺序粘贴 colnames

Paste colnames by sequence

大家好,新年快乐。

我有一个棘手的任务(在我看来),我找不到解决它的方法。 请参阅以下玩具数据。原始数据集有数百个 cols/rows.

test<-data.frame(name=c("Amber","Thomas","Stefan","Zlatan"),
             US=c(8,2,NA,7),
             UK=c(5,4,1,7))

我想创建一个名为“origin”的新列,它粘贴由“|”分隔的每个单元格(没有 NA)的列名在考虑相应的价值。应首先粘贴较高的值。至于相同的值(如 Zlatan),顺序无关紧要。 Zlatan 的输出可能是 US|UK 或 UK|US。

这是所需的输出:

我尝试了几个小时来解决它,但没有任何方法奏效。转换值 as.factor...

可能有意义

非常感谢您的帮助。提前致谢!

这是一个 dplyr 方法。首先,我们可以使用 rowwise 独立处理各个行。接下来,我们可以使用 c_across,它允许我们仅从该行获取 select 值。我们可以根据 USUK 列是否不是 NA.

c("US","UK") 的向量进行子集化

pastecollapse = "|" 允许我们将值与分隔符放在一起。我添加了一行,看看如果它们都是 NA.

会发生什么
library(dplyr)
test %>%
   rowwise() %>%
   mutate(origin = paste(c("US","UK")[rev(order(c_across(US:UK), na.last = NA))], collapse = "|"))
# A tibble: 5 x 4
# Rowwise: 
  name      US    UK origin 
  <chr>  <dbl> <dbl> <chr>  
1 Amber      8     5 "US|UK"
2 Thomas     2     4 "UK|US"
3 Stefan    NA     1 "UK"   
4 Zlatan     7     7 "UK|US"
5 Bob       NA    NA ""      

这也被简单地扩展到更多列:

test<-data.frame(name=c("Amber","Thomas","Stefan","Zlatan","Bob"),
                 US=c(8,2,NA,7,NA),
                 UK=c(5,4,1,7,NA),
                 AUS=c(1,2,NA,NA,1))

test %>%
   rowwise() %>%
   mutate(origin = paste(c("US","UK","AUS")[rev(order(c_across(US:AUS), na.last = NA))], collapse = "|"))
# A tibble: 5 x 5
# Rowwise: 
  name      US    UK   AUS origin   
  <chr>  <dbl> <dbl> <dbl> <chr>    
1 Amber      8     5     1 US|UK|AUS
2 Thomas     2     4     2 UK|AUS|US
3 Stefan    NA     1    NA UK       
4 Zlatan     7     7    NA UK|US    
5 Bob       NA    NA     1 AUS   

或在 tidyselect 协助下执行除 name:

之外的所有列
test %>%
  rowwise() %>%
  mutate(origin = paste(names(across(-name))[rev(order(c_across(-name), na.last = NA))], collapse = "|"))

这是一个不同的 tidyverse 解决方案,使用 case_when:

library(tidyverse)
data <- data.frame (test<-data.frame(
    "name" =c("Amber","Thomas","Stefan","Zlatan"),
    "US" =c(8,2,NA,7),
    "UK" =c(5,4,1,7)))

data <- data %>% mutate(origin = case_when( US >  UK ~ "US|UK", 
                                    UK >= US ~ "UK|US",
                                    is.na(UK) & !is.na(US) ~ "US", 
                                    is.na(US) & !is.na(UK) ~ "UK"))
data
#>     name US UK origin
#> 1  Amber  8  5  US|UK
#> 2 Thomas  2  4  UK|US
#> 3 Stefan NA  1     UK
#> 4 Zlatan  7  7  UK|US

reprex package (v0.3.0)

于 2021 年 1 月 6 日创建

tidyverse 的另一种可能性。它比其他两个解决方案更长,但它应该直接与具有所需列数的数据框一起使用。

我将数据框更改为长格式,过滤掉 NA,按名称分组,使用粘贴进行汇总,并与原始数据框连接以获得原始列(以及所有 NA 的行)。

library(tidyverse)

test<-data.frame(name=c("Amber","Thomas","Stefan","Zlatan","Bob"),
                 US=c(8,2,NA,7,NA),
                 UK=c(5,4,1,7,NA),
                 AUS=c(1,2,NA,NA,1))
test %>%
  # change to long format
  tidyr::pivot_longer(cols=-name, names_to = "country", values_to = "value") %>%
  # remove rows with NA
  dplyr::filter(!is.na(value)) %>%
  # group by name and sort
  dplyr::group_by(name) %>% dplyr::arrange(-value) %>%
  # create summary of countries for each name in column 'origin'
  dplyr::summarise(origin=paste(country, collapse = "|")) %>%
  # join with original data frame to include original columns (and names with only NA) and change NA to '' in origin
  dplyr::right_join(test, by='name') %>% dplyr::mutate(origin=ifelse(is.na(origin), '', origin)) %>%
  # move origin column to end
  dplyr::relocate(origin, .after = last_col())

结果

name      US    UK   AUS origin   
  <chr>  <dbl> <dbl> <dbl> <chr>    
1 Amber      8     5     1 US|UK|AUS
2 Bob       NA    NA     1 AUS      
3 Stefan    NA     1    NA UK       
4 Thomas     2     4     2 UK|US|AUS
5 Zlatan     7     7    NA US|UK