有一个月列表,需要为每个人选择最新的

时间:2018-12-19 13:08:14

标签: r date

我的数据格式如下

   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 :(得分:1)

我们通过粘贴任意日期(“ 01”),然后粘贴date group_by,将name列转换为实际日期列,并获得max行。 / p>

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

使用ave的基本R选项,我们首先转换日期,然后按组(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%

答案 1 :(得分:1)

您可以使用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月为1,12月为12。其次,它为非缩写月份名称分配一个数字。第三,它筛选出每组中分配给月份最多的行。最后,它删除了多余的变量。

答案 2 :(得分:0)

以下是使用group_byslicesplit在基座中复制lapply[的一种round回方式。

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")