Условное объединение строк в R

У меня есть этот набор данных в R:

id = 1:5
col1 = c("12 ABC", "123", "AB", "123344567", "1345677.")
col2 = c("gggw", "12", "567", "abc 123", "p")
col3 = c("abw", "abi", "klo", "poy", "17df")
col4 = c("13 AB", "344", "Huh8", "98", "b")
    
my_data = data.frame(id, col1, col2, col3, col4)

 id      col1    col2 col3  col4
1  1    12 ABC    gggw  abw 13 AB
2  2       123      12  abi   344
3  3        AB     567  klo  Huh8
4  4 123344567 abc 123  poy    98
5  5  1345677.       p 17df     b

Затем я использовал следующий код, чтобы проверить, содержит ли конкретная ячейка хотя бы одно число:

my_data$col1_check = grepl("\\d", my_data$col1)
my_data$col2_check = grepl("\\d", my_data$col2)
my_data$col3_check = grepl("\\d", my_data$col3)
my_data$col4_check = grepl("\\d", my_data$col4)

  id      col1    col2 col3  col4 col1_check col2_check col3_check col4_check
1  1    12 ABC    gggw  abw 13 AB       TRUE      FALSE      FALSE       TRUE
2  2       123      12  abi   344       TRUE       TRUE      FALSE       TRUE
3  3        AB     567  klo  Huh8      FALSE       TRUE      FALSE       TRUE
4  4 123344567 abc 123  poy    98       TRUE       TRUE      FALSE       TRUE
5  5  1345677.       p 17df     b       TRUE      FALSE       TRUE      FALSE

То, что я пытаюсь сделать, для каждой строки: я хотел бы взять все столбцы, в которых значение FALSE, и вставить (с пробелом) содержимое этих столбцов в одну ячейку.

Это будет выглядеть примерно так:

 id  new_col
1  1 gggw abw
2  2      abi
3  3   AB klo
4  4      poy
5  5      p b

Я пытался прочитать об «условной конкатенации» (например, условной конкатенации в R), но пока ничего из того, что я читал, не соответствует проблеме, над которой я работаю.

Может кто-нибудь предложить, что делать отсюда?

Спасибо!

Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
7
0
75
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Вот один из вариантов в tidyverse - зациклить across столбцы с col1 по col4, get соответствующее значение из логического столбца, paste введя _check в имена столбцов (cur_column()), преобразовать ИСТИННЫЕ значения в NA в case_when и unite эти столбцы в new_col

library(stringr)
library(dplyr)
library(tidyr)
 my_data %>%
   transmute(id, across(col1:col4, 
    ~ case_when(!get(str_c(cur_column(), "_check"))~ .x))) %>% 
   unite(new_col, col1:col4, sep = " ", na.rm = TRUE)

-вывод

 id  new_col
1  1 gggw abw
2  2      abi
3  3   AB klo
4  4      poy
5  5      p b

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

my_data %>%
   mutate(across(col1:col4,
    ~ case_when(str_detect(.x, "\\d+", negate = TRUE)  ~.x))) %>% 
   unite(new_col, col1:col4, sep = " ", na.rm = TRUE)

-вывод

  id  new_col
1  1 gggw abw
2  2      abi
3  3   AB klo
4  4      poy
5  5      p b

Или с помощью base R

cbind(my_data[1], new_col = gsub("\\s{2,}", " ", 
    trimws(do.call(paste, replace(my_data[2:5], 
     as.matrix(my_data[6:9]), '')))))

-вывод

 id  new_col
1  1 gggw abw
2  2      abi
3  3   AB klo
4  4      poy
5  5      p b

Что вы с этим делаете !get(str_c(cur_column(), "_check")~.x

TarJae 18.11.2022 20:36

@TarJae str_c добавит _check к имени столбца, а get вернет значение столбца.

akrun 18.11.2022 20:46

@user5249203 user5249203 вы можете проверить опубликованное там решение

akrun 18.11.2022 20:56

@akrun: большое спасибо за ответ! Можно ли пропустить шаг "col_check" и сделать все сразу?

stats_noob 18.11.2022 21:10

@stats_noob уверен, это можно сделать

akrun 18.11.2022 21:20

Начиная с my_data вы можете использовать

library(dplyr)
library(tidyr)
library(stringr)

my_data %>% 
  pivot_longer(-id) %>% 
  filter(!str_detect(value, "\\d")) %>% 
  group_by(id) %>% 
  summarise(new_col = paste(value, collapse = " "))

Это возвращает

# A tibble: 5 × 2
     id new_col 
  <int> <chr>   
1     1 gggw abw
2     2 abi     
3     3 AB klo  
4     4 poy     
5     5 p b  

Базовый подход R

data.frame(id = my_data$id, new_col = apply(my_data[,-1], 1, function(x) 
  paste(x[!grepl("[[:digit:]]", x)], collapse=" ")))
  id  new_col
1  1 gggw abw
2  2      abi
3  3   AB klo
4  4      poy
5  5      p b

Я имел в виду точно такой же ответ! +1

Jilber Urbina 18.11.2022 20:45

Вы можете сделать это без использования какого-либо пакета. Это может выглядеть очень утомительно, но легко понять, если вы знаете функцию apply:

data.frame(id, new_col = apply(my_data[, -1], 1, FUN = function(x) {
  paste(x[!grepl("\\d", x)], collapse = " ") }))
  
my_data

  id  new_col
1  1 gggw abw
2  2      abi
3  3   AB klo
4  4      poy
5  5      p b

Обновлен улучшенный код (спасибо @Martin Gal)

library(tidyverse)

my_data %>% 
  transmute(across(-id, ~case_when(!str_detect(., '\\d') ~ .))) %>% 
  unite("New_col", col1:col4, na.rm = TRUE, sep = " ")

Еще одно: похоже на решение @akrun, но не идентично:

library(dplyr)
library(tidyr)
library(stringr)

my_data %>% 
  transmute(across(-id, ~case_when(!str_detect(., '\\d')== TRUE ~ .), .names = 'new_{col}')) %>% 
  unite(New_col, starts_with('new'), na.rm = TRUE, sep = ' ')
   New_col
1 gggw abw
2      abi
3   AB klo
4      poy
5      p b

Вы можете опустить часть == TRUE внутрь case_when. Поскольку вы используете transmute, вы можете даже удалить .names = 'new_{col}' и starts_with('new'). :)

Martin Gal 18.11.2022 20:54

@Мартин Гал. большое спасибо. буду обновлять! Это произошло потому, что предыдущая попытка была с мутацией!

TarJae 18.11.2022 20:55

Другие вопросы по теме