Как преобразовать список (с несколькими элементами) в строку без обращения к "c (" xxx "," xxx "," xxx ")" R - PullRequest
0 голосов
/ 01 октября 2018
library(data.table)

# Target string to convert

DATE_DATA <- c("2015-01-02;2015-01-07;2021-05-02;2019-02-05",
"2017-08-02;2000-01-22;2003-03-07;2017-10-09",
"2013-08-02;2022-06-02;2012-03-15")

# Dataset
DT <- data.table(NAME = c("JOE","MARY","PAUL"),DATE = c(DATE_DATA))

Ожидаемый результат - преобразование столбца DATE в новый столбец вызывает «период», как показано ниже: разбить + отсортировать по убыванию = F + уникальный год

#  period
1: 2015,2019,2021
2: 2000,2003,2017
3: 2012,2013,2022

подходыкак показано ниже, я не вижу ожидаемого результата

# 1st approach -- RESULT : created column with class -- "list"

DT[,period:= lapply(strsplit(DT$DATE,";"),
                                 function(x) sort(unique(str_sub(x,1,4)),
                                                  decreasing = FALSE))]

# 2nd approach -- RESULT : created column with class -- "character" but value
#                          turn to "c("xxx", "xxx", "xxx")" , not expected 
#                          "xxx,xxx,xxx"

DT[,period:= as.character(paste(lapply(strsplit(DT$DATE,";"),
                             function(x) sort(unique(str_sub(x,1,4)),
                                              decreasing = FALSE)),collapse = ","))]

Какой шаг я пропустил?Заранее спасибо

Ответы [ 3 ]

0 голосов
/ 01 октября 2018

Мы можем сделать это, используя gsub и scan

DT[,  Period := toString(sort(unique(scan(text=gsub("-\\d+", 
               "", DATE), what = numeric(), sep=";")))), NAME]
DT
#   NAME                                        DATE           Period
#1:  JOE 2015-01-02;2015-01-07;2021-05-02;2019-02-05 2015, 2019, 2021
#2: MARY 2017-08-02;2000-01-22;2003-03-07;2017-10-09 2000, 2003, 2017
#3: PAUL            2013-08-02;2022-06-02;2012-03-15 2012, 2013, 2022

Или другой вариант - tidyverse, где мы преобразуем в «длинный» формат, разделив «DATE» в;, сгруппированные по 'NAME', summarise 'Period' в виде sort ed year преобразованного класса Date (ymd), выполните объединение с исходным набором данных и selectстолбцы в соответствующем порядке (при необходимости)

library(tidyverse)
DT %>% 
   separate_rows(DATE, sep = ";") %>% 
   group_by(NAME) %>% 
   summarise(Period = toString(sort(unique(year(ymd(DATE)))))) %>% 
   right_join(DT) %>%
   select(names(DT), everything())
# A tibble: 3 x 3
#  NAME  DATE                                        Period                
#  <chr> <chr>                                       <chr>                 
#1 JOE   2015-01-02;2015-01-07;2021-05-02;2019-02-05 2015, 2019, 2021
#2 MARY  2017-08-02;2000-01-22;2003-03-07;2017-10-09 2000, 2003, 2017
#3 PAUL  2013-08-02;2022-06-02;2012-03-15            2012, 2013, 2022    
0 голосов
/ 02 октября 2018

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

DT[, period:=sapply(strsplit(DATE, ";"), 
     function(x) paste(sort(unique(year(as.Date(x)))), collapse = ","))]

В результате получается:

   NAME                                        DATE         period
1:  JOE 2015-01-02;2015-01-07;2021-05-02;2019-02-05 2015,2019,2021
2: MARY 2017-08-02;2000-01-22;2003-03-07;2017-10-09 2000,2003,2017
3: PAUL            2013-08-02;2022-06-02;2012-03-15 2012,2013,2022

strsplit(DATE, ";") даст вам столбец списка типов.Это означает, что вы можете применить функцию lapply к этому столбцу, которая будет брать каждую строку и применять к ней некоторую функцию.Тогда вопрос только в том, как преобразовать вектор символов ваших дат в отсортированные годы

0 голосов
/ 01 октября 2018

Для каждого DATE мы можем разделить столбец DATE на «;», преобразовать их в дату, извлечь год, используя format, взять уникальные годы и вставить их вместе, используя toString.

DT$Period <- sapply(DT$DATE, function(x) 
         toString(sort(unique(format(as.Date(strsplit(x, ";")[[1]]), "%Y")))))
DT

#   NAME                                        DATE           Period
#1:  JOE 2015-01-02;2015-01-07;2021-05-02;2019-02-05 2015, 2019, 2021
#2: MARY 2017-08-02;2000-01-22;2003-03-07;2017-10-09 2000, 2003, 2017
#3: PAUL            2013-08-02;2022-06-02;2012-03-15 2012, 2013, 2022

Мы можем уменьшить шаг as.Date и format, используя функцию year из пакета lubridate, которая дает тот же результат.

library(lubridate)
DT$Period <- sapply(DT$DATE, function(x) 
                   toString(sort(unique(year(strsplit(x, ";")[[1]])))))

Iя не эксперт по data.table, но я думаю, что вы упускаете из своей попытки параметр группирования (by), потому что в настоящее время он дает вам уникальный год из всего столбца DATE, вам нужно указать, что вынужно unique год для каждой строки отдельно, что упоминается в аргументе by.

DT[,period:= paste(sapply(strsplit(DATE,";"),
  function(x) sort(unique(substr(x,1,4)),)),collapse = ","), by = 1:nrow(DT)]

DT

#   NAME                                        DATE         period
#1:  JOE 2015-01-02;2015-01-07;2021-05-02;2019-02-05 2015,2019,2021
#2: MARY 2017-08-02;2000-01-22;2003-03-07;2017-10-09 2000,2003,2017
#3: PAUL            2013-08-02;2022-06-02;2012-03-15 2012,2013,2022
...