Если элементы разные, свернуть

#r #database #dataframe #collapse

#r #База данных #фрейм данных

Вопрос:

У меня есть два столбца, которые я хочу свернуть, если они разные. Если они одинаковые, просто сохраните значение. Если есть один NA , сохраните другой.

 df
#   element1 element2
#1        A         
#2        B        B
#3        C        D
#4        A     <NA>
  

И мне нужен следующий столбец:

 #  element1 element2 element12
#1        A                  A
#2        B        B         B
#3        C        D       C,D
#4        A     <NA>         A
  

Любой намек на то, как я могу это сделать?

Данные:

 df = data.frame(element1 = c("A", "B",  "C","A"),
                 element2 = c("", "B","D", NA));df
  

Ответ №1:

Попробуйте этот подход с apply() :

 #Code 1
df$Var <- apply(df[1:2],1,function(x) trimws(paste0(unique(x[!is.na(x)]),collapse = ','),
                                             whitespace = ','))
  

Вывод:

   element1 element2 Var
1        A            A
2        B        B   B
3        C        D C,D
4        A     <NA>   A
  

Или dplyr версия:

 library(dplyr)
#Code
df %>% mutate(across(everything(),~as.character(.))) %>%
  replace(is.na(.),',') %>%
  rowwise() %>%
  mutate(Var=trimws(paste0(unique(c_across(element1:element2)),
                                              collapse = ','),whitespace = ',')) %>%
  replace(.==',',NA)
  

Вывод:

 # A tibble: 4 x 3
# Rowwise: 
  element1 element2 Var  
  <chr>    <chr>    <chr>
1 A        ""       A    
2 B        "B"      B    
3 C        "D"      C,D  
4 A         NA      A  
  

Комментарии:

1. Хорошая утка, лаконичная и быстрая еще раз.

2. Утка, я вижу без аргумента пробела, в первой строке после A стоит запятая. Он заменяет ‘,’ пробелом, а затем trimws удаляет его?

Ответ №2:

Работает ли это:

 > df %>% mutate(element3 = case_when(
There were 14 warnings (use warnings() to see them)
                                    element1 == element2 ~ element1,
                                    is.na(element1) amp; !is.na(element2) ~ element2,
                                    is.na(element2) amp; !is.na(element1) ~ element1,
                                    element1 == '' amp; element2 != '' ~ element2,
                                    element1 != '' amp; element2 == '' ~ element1,
                                    element1 != element2 ~ paste(element1, element2, sep = ',')
  ))
  element1 element2 element3
1        A                 A
2        B        B        B
3        C        D      C,D
4        A     <NA>        A
> 
  

Ответ №3:

Вот еще tidyverse один вариант.

Если вы хотите избавиться от раздражающих пустых строк "" и создать их NA , вы можете использовать na_if .

A case_when может объединить строки, если они разные, с coalesce использованием в случае, если один или другой отсутствует ( NA ) .

Если ни то, ни другое не так, то оба столбца одинаковы и просто устанавливаются в качестве первого значения.

 library(tidyverse)

df %>%
  na_if("") %>%
  mutate(element12 = case_when(
    element1 != element2 ~ paste(element1, element2, sep = ','),
    is.na(element1) | is.na(element2) ~ coalesce(element1, element2),
    TRUE ~ element1))
  

Вывод

   element1 element2 element12
1        A     <NA>         A
2        B        B         B
3        C        D       C,D
4        A     <NA>         A
  

Ответ №4:

В base R , мы можем сделать это с paste помощью и sub

 df$elements12 <- gsub("(?<=.)(?=.)", ",", sub("(.)\1 ", "\1", 
     do.call(paste, c(replace(df, is.na(df), ""), sep=""))), perl = TRUE)
  

-вывод

 df$element12
#[1] "A"   "B"   "C,D" "A"