使用带有日期(例如“8月14日”)的“lubridate”包编写R函数并返回星座

问题描述 投票:2回答:2

声明:编写一个接受日期作为输入的函数,并返回与该日期对应的黄道带的星座(使用Lubridate包)。

问题:当我输入“Dec 22”和“Jan 19”之间的任何日期时。它返回NULLymd应该返回2017-12-22 UTC--2018-01-19 UTC而不是2017-12-22 UTC--2017-01-19 UTC

有没有更好的方法来生成Date / POSIx数据的间隔?

zodiac_sign <- function(input){

  library(lubridate)

  input <- ymd(as.character(as.Date(input,format="%B %d")))

  x <- as.Date(c("March 21","April 19","April 20","May 20","May 21","June 20","June 21","July 22","July 23","August 22","August 23","September 22","September 23","October 22","October 23","November 21","November 22","December 21","December 22","January 19","January 20","February 18","February 19","March 20"),format="%B %d")

  x_dateform_char <- as.character(x)

  lst <- list()

  for(i in seq(1,length(x_dateform_char),2)) { 
    lst[[i]] <- c(ymd(x_dateform_char[i]) %--% ymd(x_dateform_char[i+1]))
    if(i==(length(x_dateform_char)-1)){
      break 
    }
  }

  lst <- lst[!sapply(lst, is.null)]

  names(lst) <-
    c("Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittari
      us","Capricorn","Aquarius","Pisces")

  lst

  for(i in 1:length(lst)){
    if(input %within% lst[[i]]){ 
      sign <- names(lst)[i] 
    } }
  sign 
}
r date lubridate
2个回答
2
投票

黄道带标志通常取决于月份的日期,而年份不起任何作用。因此,我想尝试完全忽略评估逻辑中的年份部分。

我考虑的逻辑是基于日期(一个月的day),它在那个月划分黄道十二宫。然后只需从输入值中明确考虑monthday部分。

zodiac_sign <- function(input){
  library(lubridate)

  input <- ymd(as.character(as.Date(input,format="%B %d")))

  # Define data.frame for zodiac_sign
  zodiac_sign_df <- data.frame(Month = c("March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February"),
                               Zodiac_Separation_Dt = c(21, 20, 21, 21, 23, 23, 23, 23, 22, 22, 20, 19),
                               LowerSideZS = c("Pisces", "Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius"),
                               UpperSideZS = c("Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius", "Pisces"),
                               stringsAsFactors = FALSE )

  # Filter data with matching month
  val_df <- zodiac_sign_df[zodiac_sign_df$Month == months(input), ] 


  zodiac_sign <- ifelse( day(input) >= val_df$Zodiac_Separation_Dt, val_df$UpperSideZS, val_df$LowerSideZS)  

  zodiac_sign
}

上面逻辑中使用的zodiac_sign_df看起来像:

> zodiac_sign_df
       Month Zodiac_Separation_Dt LowerSideZS UpperSideZS
1      March                   21      Pisces       Aries
2      April                   20       Aries      Taurus
3        May                   21      Taurus      Gemini
4       June                   21      Gemini      Cancer
5       July                   23      Cancer         Leo
6     August                   23         Leo       Virgo
7  September                   23       Virgo       Libra
8    October                   23       Libra     Scorpio
9   November                   22     Scorpio Sagittarius
10  December                   22 Sagittarius   Capricorn
11   January                   20   Capricorn    Aquarius
12  February                   19    Aquarius      Pisces

1
投票

我重新编辑了您的代码以生成您需要的结果

zodiac_sign <- function(input){
  nms<- input
  library(lubridate)

  input <-ymd(as.character(as.Date(input,format="%B %d")))

  x <- as.Date(c("January 20","February 18",
                 "February 19","March 20","March 21","April 19","April 20","May 20","May 21","June 20",
                 "June 21","July 22","July 23","August 22","August 23","September 22",
                 "September 23","October 22","October 23","November 21","November 22",
                 "December 21","December 22","January 19"),format="%B %d")
  zodiac_name<-c("Aquarius","Pisces","Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra",
                 "Scorpio","Sagittarius","Capricorn")

  lst=lapply(split(x,rep(1:12,each=2)),function(y){if(y[2]<y[1])y[2]=y[2]+365;c(y[1]%--%y[2])})
  limit=format(ymd(as.character(as.Date("Jan 20",format="%B %d"))),format="%m-%d")
  lower=format(input,format="%m-%d")<limit
  input[lower]=input[lower]+365


  result=which(mapply(`%within%`,list(input),lst),T)
   if(is.matrix(result))setNames(zodiac_name[result[order(result[,1]),2]],nms)
  else setNames(zodiac_name[result],nms)
}
zodiac_sign(c("Jan 10","Mar 20", "Aug 30", "Sep 25","Dec 22","Dec 25"))
     Jan 10      Mar 20      Aug 30      Sep 25      Dec 22      Dec 25 
"Capricorn"    "Pisces"     "Virgo"     "Libra" "Capricorn" "Capricorn" 
© www.soinside.com 2019 - 2024. All rights reserved.