Мутировать столбцы так, чтобы базовые имена совпадали - PullRequest
1 голос
/ 14 июня 2019

Предположим, у меня есть вектор пути к файлу, который я разделил на "/" и поместил в фрейм данных. Эти пути к файлам имеют различную длину, но в конце дня я хочу, чтобы все базовые имена были выстроены в одном столбце. Ниже я привел пример того, что я имею в виду, и желаемый результат.

library(tidyverse)

dat <- tibble(
    V1 = rep("run1", 5),
    V2 = rep("ox", 5),
    V3 = c("performance.csv", "analysis", "analysis", "performance.csv", "analysis"),
    V4 = c("", "rod1", "rod2", "rod3", "performance.csv"), 
    V5 = c("", "performance.csv", "performance.csv", "performance.csv", "")
)

dat
#> # A tibble: 5 x 5
#>   V1    V2    V3              V4              V5             
#>   <chr> <chr> <chr>           <chr>           <chr>          
#> 1 run1  ox    performance.csv ""              ""             
#> 2 run1  ox    analysis        rod1            performance.csv
#> 3 run1  ox    analysis        rod2            performance.csv
#> 4 run1  ox    performance.csv rod3            performance.csv
#> 5 run1  ox    analysis        performance.csv ""

output <- tibble(
    V1 = rep("run1", 5),
    V2 = rep("ox", 5),
    V3 = c("", "analysis", "analysis", "", "analysis"),
    V4 = c("", "rod1", "rod1", "rod2", ""), 
    V5 = c("performance.csv", "performance.csv", "performance.csv", "performance.csv", "performance.csv")
)

output
#> # A tibble: 5 x 5
#>   V1    V2    V3       V4    V5             
#>   <chr> <chr> <chr>    <chr> <chr>          
#> 1 run1  ox    ""       ""    performance.csv
#> 2 run1  ox    analysis rod1  performance.csv
#> 3 run1  ox    analysis rod1  performance.csv
#> 4 run1  ox    ""       rod2  performance.csv
#> 5 run1  ox    analysis ""    performance.csv

Моя мысль состоит в том, чтобы прибегнуть к циклу for, в котором я проверяю, содержит ли столбец базовое имя, и если да, замените его на "" и переместите его в последний столбец. У меня проблемы с формированием этой логики, и я знаю, что должен быть лучший способ использовать Tidyverse.

Ответы [ 3 ]

6 голосов
/ 14 июня 2019

Создайте функцию rearrange, которая переставляет строку, помещая базовое имя в конец, удаляя его исходное положение, если оно еще не находится в конце. Мы предполагаем, что любая запись с точкой является базовым именем. Затем примените rearrange к каждой строке.

rearrange <- function(x) {
  i <- grep(".", x, fixed = TRUE)[1]
  x[length(x)] <- x[i]
  if (i < length(x)) x[i] <- ""
  x
}
as_tibble(t(apply(dat, 1, rearrange)))

дает:

# A tibble: 5 x 5
  V1    V2    V3       V4    V5             
  <chr> <chr> <chr>    <chr> <chr>          
1 run1  ox    ""       ""    performance.csv
2 run1  ox    analysis rod1  performance.csv
3 run1  ox    analysis rod2  performance.csv
4 run1  ox    ""       rod3  performance.csv
5 run1  ox    analysis ""    performance.csv
1 голос
/ 14 июня 2019

Опция с base R с использованием max.col. Получите индекс столбца подмножества набора данных (с 3-го по 5-й столбец), где . как элемент, cbind с индексом строки (seq_len(nrow(dat))), извлеките элементы из набора данных на основе этого индекса и назначьте его 'V5. Затем измените 3-й и 4-й столбцы на основе ИСТИННЫХ значений логической матрицы (do.call(cbind, .) на пустое ("")

dat <- as.data.frame(dat)
lst1 <- lapply(dat[3:5], grepl, pattern = '\\.')
ij <- cbind(seq_len(nrow(dat)), max.col(do.call(cbind, lst1), 'first'))
dat$V5 <-  dat[3:5][ij]
dat[3:4][do.call(cbind, lst1[1:2])] <- ""
dat
#    V1 V2       V3   V4              V5
#1 run1 ox               performance.csv
#2 run1 ox analysis rod1 performance.csv
#3 run1 ox analysis rod2 performance.csv
#4 run1 ox          rod3 performance.csv
#5 run1 ox analysis      performance.csv

Или используя tidyverse с coalesce. Здесь мы select столбцы 'V3' до 'V5', циклически перебирая столбцы (map), replace элементы, которые не .csv с NA, coalesce это один столбец, свяжите этот столбец с подмножеством столбцов исходного набора данных и replace с 3-го по 4-й столбцы, которые имеют . до пробела ("")

library(tidyverse)
dat %>% 
  select(V3:V5) %>% 
  map_df(~ replace(.x, str_detect(.x, "\\.csv", negate = TRUE), NA)) %>% 
  transmute(V5 = coalesce(!!! .)) %>%
  bind_cols(dat %>% 
             select(-V5), .) %>% 
  mutate_at(vars(3:4), list(~ replace(., str_detect(., "\\."), '')))
# A tibble: 5 x 5
#  V1    V2    V3       V4    V5             
#  <chr> <chr> <chr>    <chr> <chr>          
#1 run1  ox    ""       ""    performance.csv
#2 run1  ox    analysis rod1  performance.csv
#3 run1  ox    analysis rod2  performance.csv
#4 run1  ox    ""       rod3  performance.csv
#5 run1  ox    analysis ""    performance.csv
1 голос
/ 14 июня 2019

Вот способ tidyverse -

dat %>% 
  rownames_to_column("id") %>% 
  gather(key, variable, -id) %>% 
  group_by(id) %>% 
  mutate(
    variable = case_when(
      key == "V5" ~ tail(grep(".csv", x = variable, value = T), 1),
      key != "V5" & grepl(".csv", x = variable) ~ "",
      TRUE ~ variable
    )
  ) %>% 
  ungroup() %>% 
  spread(key, variable)


# A tibble: 5 x 6
  id    V1    V2    V3       V4    V5             
  <chr> <chr> <chr> <chr>    <chr> <chr>          
1 1     run1  ox    ""       ""    performance.csv
2 2     run1  ox    analysis rod1  performance.csv
3 3     run1  ox    analysis rod2  performance.csv
4 4     run1  ox    ""       rod3  performance.csv
5 5     run1  ox    analysis ""    performance.csv
...