есть список месяцев, нужно выбрать последний для каждого человека - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть данные в следующем формате

   name  date          x  y  z 
    a    March-2018    1  2  2
    a    Feb-2018      2  3  3
    b    June-2017     3  4  4
    b    April-2017    4  5  5
    c    Sep-2018      5  5  6
    c    Aug-2017      7  7  8

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

   name  date          x  y  z 
    a    March-2018    1  2  2
    b    June-2017     3  4  4
    c    Sep-2018      5  5  6

Я пробовал с разными именами и выбралМаксимальная дата, но не тренировки.

Ответы [ 3 ]

0 голосов
/ 19 декабря 2018

Используя tidyverse, вы можете сделать:

df %>%
 mutate(temp = match(gsub("-.*$", "", date), month.abb), 
        temp2 = ifelse(is.na(temp), match(gsub("-.*$", "", date), month.name), temp)) %>%
 group_by(name) %>%
 filter(temp2 == max(temp2)) %>%
 select(-starts_with("temp"))
  name  date           x     y     z
  <fct> <fct>      <int> <int> <int>
1 a     March-2018     1     2     2
2 b     June-2017      3     4     4
3 c     Sep-2018       5     5     6

Сначала вынимаются названия месяцев из «даты», а затем присваивается номер сокращенным названиям месяцев, где январь равен 1, а декабрь -12. Во-вторых, он присваивает номер не сокращенным названиям месяцев.В-третьих, он отфильтровывает строки в группе с наибольшим числом, назначенным месяцам.Наконец, он удаляет избыточные переменные.

0 голосов
/ 19 декабря 2018

Ниже представлен обходной способ репликации group_by и slice в базе с использованием split и lapply с [.

do.call(rbind, 
lapply(split(df, df$name), 
       function(x) x[which.max(as.Date(paste0("01-", x$date), "%d-%b-%Y")),])
)
#   name       date x y z
# a    a March-2018 1 2 2
# b    b  June-2017 3 4 4
# c    c   Sep-2018 5 5 6

Другой вариант - aggregate, а затемmerge.Похоже, может быть какой-то другой способ сделать это на базе, по которой я скучаю.

to.keep <- 
  aggregate(date ~ name, data = df, 
            function(x) x[which.max(as.Date(paste0("01-", x), "%d-%b-%Y"))])

merge(df, to.keep, by = names(to.keep))

#   name       date x y z
# a    a March-2018 1 2 2
# b    b  June-2017 3 4 4
# c    c   Sep-2018 5 5 6

Используемые данные

structure(list(name = c("a", "a", "b", "b", "c", "c"), date = c("March-2018", 
"Feb-2018", "June-2017", "April-2017", "Sep-2018", "Aug-2017"
), x = c(1L, 2L, 3L, 4L, 5L, 7L), y = c(2L, 3L, 4L, 5L, 5L, 7L
), z = c(2L, 3L, 4L, 5L, 6L, 8L)), row.names = c(NA, -6L), class = "data.frame")
0 голосов
/ 19 декабря 2018

Мы преобразуем столбец date в столбец фактической даты, вставляя произвольную дату ("01"), затем group_by name и получаем строку max.

library(dplyr)
df %>%
   mutate(newdate = as.Date(paste0("01-", date), "%d-%b-%Y")) %>%
   group_by(name) %>%
   slice(which.max(newdate)) %>%
   select(-newdate)

 #   name     date           x     y     z
 #  <fct>     <fct>      <int> <int> <int>
 #1   a     March-2018     1     2     2
 #2   b     June-2017      3     4     4
 #3   c     Sep-2018       5     5     6

Базовая опция R с использованием ave, мы сначала конвертируем даты, а затем получаем max даты по группе (name) и подставляем их из исходного кадра данных.

df$new_date <- as.Date(paste0("01-", df$date), "%d-%b-%Y")
#I was trying to use which.max instead of max but it giving me an error, not sure why
df[with(df, new_date %in% ave(new_date, name, FUN = max)), ]

# name       date x y z   new_date
#1    a March-2018 1 2 2 2018-03-01
#3    b  June-2017 3 4 4 2017-06-01
#5    c   Sep-2018 5 5 6 2018-09-01

Примечание - какупомянутый @ IceCreamToucan ave метод работает здесь, потому что каждый name имеет разные max date, если дата одна и та же, это может дать разные результаты, так как мы используем %in% здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...