Условное объединение строк в 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), но пока ничего из того, что я читал, не соответствует проблеме, над которой я работаю.

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

Спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
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

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