Как отсортировать строку в R, содержащую числа, разделенные запятыми - PullRequest
0 голосов
/ 06 августа 2020

У меня есть следующий фрейм данных:

library(tidyverse)
library(tibble)
data_frame <-
  tribble(
    ~a,                                                 ~b,
    "2,29,3,30,31,4,5,2,28,29,3,30,4,5",                "x",
    "12,13,14,15,18,19,20,12,13,14,15,18,19,20,21" ,     "y"
  )

Я хочу создать новый столбец для этого фрейма данных с именем c, который может отображать строки в a, расположенные в порядке возрастания числовых значений. C в идеале должен выглядеть следующим образом:

library(tidyverse)
library(tibble)
data_frame <-
  tribble(
    ~a,                                                 ~b,            ~c,
    "2,29,3,30,31,4,5,2,28,29,3,30,4,5",                "x",           "2,2,3,3,4,4,5,5,28,29,29,30,30,31"
    "12,13,14,15,18,19,20,12,13,14,15,18,19,20,21" ,     "y",          "12,12,13,13,14,14,15,15,18,18,19,19,20,20,21"
  )

Как я могу этого добиться? Я пробовал использовать str_sort из пакета stringr, а также функцию mixedsort из библиотеки gtools. Спасибо.

Ответы [ 3 ]

2 голосов
/ 06 августа 2020

В tidyverse мы можем использовать separate_rows при преобразовании type, чтобы разделить 'a' разделителем, затем arrange столбцы 'b', 'a', сгруппированные по 'b' , paste элементы 'a' в новом столбце и свяжите его с исходным набором данных

library(dplyr)
library(tidyr)
 data_frame %>% 
    # // split a by the delimiter and expand the rows
    separate_rows(a, convert = TRUE) %>%
     # // order the columns
     arrange(b, a) %>%
     # // grouped by b
     group_by(b) %>%
     # paste the elements of a
     # toString => paste(..., collapse=", ") 
     summarise(c = toString(a)) %>%
     # // select the column c
     select(c) %>%
     # // bind with the original dataset
     bind_cols(data_frame, .) 
# A tibble: 2 x 3
#  a                                            b     c                                                         
#  <chr>                                        <chr> <chr>                                                     
#1 2,29,3,30,31,4,5,2,28,29,3,30,4,5            x     2, 2, 3, 3, 4, 4, 5, 5, 28, 29, 29, 30, 30, 31            
#2 12,13,14,15,18,19,20,12,13,14,15,18,19,20,21 y     12, 12, 13, 13, 14, 14, 15, 15, 18, 18, 19, 19, 20, 20, 21

Или используя strsplit с map. Мы разделяем строку 'a' на ,, l oop на list на map, конвертируем в numeric, sort, а затем paste в одну строку

library(purrr)
data_frame %>% 
   mutate(c = map_chr(strsplit(a, ","), ~ 
                  toString(sort(as.numeric(.x)))))
# A tibble: 2 x 3
#  a                                            b     c                                                         
#  <chr>                                        <chr> <chr>                                                     
#1 2,29,3,30,31,4,5,2,28,29,3,30,4,5            x     2, 2, 3, 3, 4, 4, 5, 5, 28, 29, 29, 30, 30, 31          
#2 12,13,14,15,18,19,20,12,13,14,15,18,19,20,21 y     12, 12, 13, 13, 14, 14, 15, 15, 18, 18, 19, 19, 20, 20, 21           
1 голос
/ 06 августа 2020

Используя mixedsort из gtools:

data_frame$c <- sapply(strsplit(data_frame$a, ','), function(x) 
                       toString(gtools::mixedsort(x)))

Это можно записать в tidyverse как:

library(tidyverse)
data_frame %>%
   mutate(c = str_split(a, ','), 
          c = map_chr(c, ~toString(gtools::mixedsort(.x))))
1 голос
/ 06 августа 2020

Для базовой опции R мы можем использовать strsplit для генерации вектора чисел, затем отсортировать этот вектор и, наконец, свернуть обратно в строку символов.

x <- "2,29,3,30,31,4,5,2,28,29,3,30,4,5"
nums <- sort(as.numeric(strsplit(x, ",")[[1]]))
output <- paste(nums, collapse=",")
output

[1] "2,2,3,3,4,4,5,5,28,29,29,30,30,31"

Для версии, которая работает на целые фреймы данных:

nums <- c("2,29,3,30,31,4,5,2,28,29,3,30,4,5",
          "12,13,14,15,18,19,20,12,13,14,15,18,19,20,21")
df <- data.frame(v1=nums, stringsAsFactors=FALSE)
df$v2 <- lapply(df$v1, function(y) paste(sort(as.numeric(strsplit(y, ",")[[1]])), collapse=","))
df

                                            v1
1            2,29,3,30,31,4,5,2,28,29,3,30,4,5
2 12,13,14,15,18,19,20,12,13,14,15,18,19,20,21
                                            v2
1            2,2,3,3,4,4,5,5,28,29,29,30,30,31   # sorted
2 12,12,13,13,14,14,15,15,18,18,19,19,20,20,21   # sorted
...