ありハックのカップルがあり、その利便性は、あなたがmeteorological or astronomical seasonsを使用するかどうかに依存します。私は両方を提供する、私は彼らが十分な柔軟性を提供すると思います。
提供された2番目のデータは、「冬」以上のものを提供するため、使用します。
txt <- "date name count
2016-11-12 Joe 5
2016-11-15 Bob 5
2017-06-15 Nick 12
2017-10-16 Cate 6"
dat <- read.table(text = txt, header = TRUE, stringsAsFactors = FALSE)
dat$date <- as.Date(dat$date)
季節が厳密に月によって定義されている場合、最も速い方法がうまくいきます。
metseasons <- c(
"01" = "Winter", "02" = "Winter",
"03" = "Spring", "04" = "Spring", "05" = "Spring",
"06" = "Summer", "07" = "Summer", "08" = "Summer",
"09" = "Fall", "10" = "Fall", "11" = "Fall",
"12" = "Winter"
)
metseasons[format(dat$date, "%m")]
# 11 11 06 10
# "Fall" "Fall" "Summer" "Fall"
あなたがそのような天文季節として停止/月の開始によって定義されていない、あなたの季節のための日付範囲を使用することを選択した場合は、ここでは別の「ハック」はです:
astroseasons <- as.integer(c("0000", "0320", "0620", "0922", "1221", "1232"))
astroseasons_labels <- c("Winter", "Spring", "Summer", "Fall", "Winter")
あなたが適切なDate
を使用している場合またはPOSIX
タイプの場合は、年を含めているため、一般的なものになります。ユリウス暦の日付を使用すると考えられるかもしれませんが、うるう年には異常が生じます。したがって、2月28日は決して季節的な境界ではないという前提で、私は月の日を「数値化」しています。 Rは文字比較をうまく行っても、cut
は数字を期待しているので、整数に変換します。
二セーフガード:cut
はどちらか右開き(およびクローズ左)または右閉じた我々の2つのブックエンドがを超えて法的な日数をを拡張する必要があり、その後、(左開き)、エルゴであるため、 "0000"
および"1232"
。ここでも同様に機能する他の手法があります(たとえば、-Inf
およびInf
、ポスト整数化を使用)。
astroseasons_labels[ cut(as.integer(format(dat$date, "%m%d")), astroseasons, labels = FALSE) ]
# [1] "Fall" "Fall" "Spring" "Fall"
天気予報の季節とそれ以外の場合は3番目の日付は春です。
この解決法は、南半球または他の季節の好み/考え方を考慮して簡単に調整することができます。
を編集:@Kristofersen's answer(ありがとう)によって、私はベンチマークを調べました。 lubridate::month
はPOSIXct
-to-POSIXlt
の変換を使用して月を抽出します。これは私のformat(x, "%m")
メソッドよりも10倍以上速くなります。そのように:
metseasons2 <- c(
"Winter", "Winter",
"Spring", "Spring", "Spring",
"Summer", "Summer", "Summer",
"Fall", "Fall", "Fall",
"Winter"
)
留意as.POSIXlt
戻り0ベースヶ月つまり、私たちは1を追加します。
metseasons2[ 1 + as.POSIXlt(dat$date)$mon ]
# [1] "Fall" "Fall" "Summer" "Fall"
比較:
library(lubridate)
library(microbenchmark)
set.seed(42)
x <- Sys.Date() + sample(1e3)
xlt <- as.POSIXlt(x)
microbenchmark(
metfmt = metseasons[ format(x, "%m") ],
metlt = metseasons2[ 1 + xlt$mon ],
astrofmt = astroseasons_labels[ cut(as.integer(format(x, "%m%d")), astroseasons, labels = FALSE) ],
astrolt = astroseasons_labels[ cut(100*(1+xlt$mon) + xlt$mday, astroseasons, labels = FALSE) ],
lubridate = sapply(month(x), seasons)
)
# Unit: microseconds
# expr min lq mean median uq max neval
# metfmt 1952.091 2135.157 2289.63943 2212.1025 2308.1945 3748.832 100
# metlt 14.223 16.411 22.51550 20.0575 24.7980 68.924 100
# astrofmt 2240.547 2454.245 2622.73109 2507.8520 2674.5080 3923.874 100
# astrolt 42.303 54.702 72.98619 66.1885 89.7095 163.373 100
# lubridate 5906.963 6473.298 7018.11535 6783.2700 7508.0565 11474.050 100
のでas.POSIXlt(...)$mon
を用いる方法が大幅に高速化されています。 (@ Kristofersenの答えは、ifelse
でベクトル化することで改善することができますが、cut
の有無にかかわらず、ベクトルルックアップの速度とはまだ比較されません)。
ありがとうございます。これを実装しようとしたとき、シーズンの列にすべてのNAがありました。なぜこれができるのか知っていますか? – Amanda
私の悪いことに、 'match'の' dfSeason'は 'dfSeason $ month'です – din