1

私は中規模のデータセットを持っています。これはデータセットから取られた例です:

2011.2012
9/7 
11/5
12/15
1/5
2/5

このデータを時系列形式に変換したいと思います。

因子から文字に変換した後、as.Dates関数を使用しましたが、不具合が発生しました。

結果は、欠落している年が現在の年であると想定しています。私の目標は、1/1 より前の日付を 2011 年に変換し、1/1 より後の日付を 2012 年に変換できるようにすることです。データの範囲は 2011 年 9 月から 2012 年 4 月までです。

origin と start を使用してみましたが、役に立ちませんでした。ここに私のコードがあります:

date1 <- as.character(2011.2012)
date1 <- as.Date(date1, format="%m/%d") 
4

3 に答える 3

6

6月/7月に分割するのはどうですか?これは、日付の形式によって異なります。

> x=c("9/7", "11/5", "12/15", "1/5", "2/5" )
> sapply(strsplit(x, '/')
         , function(x) paste(if(as.numeric(x[1]) > 6) 2011 else 2012, x[1], x[2]
                             , sep="/"
                            )
        )

[1] "2011/9/7"   "2011/11/5"  "2011/12/15" "2012/1/5"   "2012/2/5"  

以下は、上記のベクトル化されたアプローチで、 ではifelseなくを使用しifます。

mm <- matrix(nrow=2, unlist(strsplit(x, '/')))
paste(ifelse(as.numeric(mm[1,]) > 6, 2011, 2012), mm[1,], mm[2,], sep='/')

[1] "2011/9/7"   "2011/11/5"  "2011/12/15" "2012/1/5"   "2012/2/5"  

ベクトル化されたアプローチは読みにくくなりますが、はるかに高速です (1.7 倍)。

Date関数を使用して、月の回帰を探して、@MarkMiller のアプローチをベクトル化する方法の 1 つを次に示します。

initialYear <- 2011

dd <- as.Date(x, "%m/%d")
mon <- format(dd, "%m")
as.Date(paste(initialYear + c(0, cumsum(diff(as.numeric(mon))<0))
                , mon
                , format(dd, "%d")
                , sep="-"
                )
          )

[1] "2011-09-07" "2011-11-05" "2011-12-15" "2012-01-05" "2012-02-05"

おそらくすべてのDate関数が原因で、これは上記のベクトル化されたアプローチよりも実行に 3.6 倍長くかかります (ファイナルas.Dateが削除された場合は 2.6 倍)。これは 2011 と 2012 に限定されています。 3 つsapplyの と明示的なforループ。

于 2012-12-30T06:11:06.877 に答える
3

これが私が思いついたものです。このコードが常に機能するかどうかはわかりませんが、使用したサンプル データ セットでは機能するようです。コードは 2 年以上、年中いつでも処理できるようです。

コードはデータのない年を処理できませんが、年がデータ セットにない場合、そのようなギャップはおそらく特定できません。

また、このアプローチは、「1/30」と「3/1」の 2 つの日付で失敗することにも注意してください。2 つの日付が 2 年連続した場合です。これは、2 つの日付の間に非常に大きな隔たりがあるため、コンピューターが 2 つの日付が同じ年ではないことを認識する方法がないためです。

言い換えれば、2 つの連続する日付の間に非常に長いギャップがある場合、追加情報がなければ、どのアプローチも失敗する可能性があります。たとえば、四半期ごとまたは半年ごとに少なくとも1つの日付がある場合、コンピューターは連続した月の減少を新しい年を示すものとして識別できるため、投稿された両方の回答が機能すると思います.

連続する 2 つの日付間の最長の間隔が 11 か月である場合、両方のアプローチが機能する可能性があります。連続する 2 つの日付のそれぞれの日もチェックするようにコードを修正すれば、363 日のギャップは問題ないかもしれません。

# specify the initial year and create dates from the data

initial.year = 2010

date  <- c("12/30", "1/1", "6/1", "6/1", "10/25", "11/27", "12/28", 
           "1/16", "2/17", "2/17", "2/17")

DDD3  <- as.Date(date, format="%m/%d")

# deconstruct dates into month, day and erroneous year

dtstr <- as.character(DDD3)
month <- as.numeric(as.character(sapply(strsplit(dtstr, "-") , "[", 2)))
day   <- as.numeric(as.character(sapply(strsplit(dtstr, "-") , "[", 3)))
year  <- as.numeric(as.character(sapply(strsplit(dtstr, "-") , "[", 1)))
DDD4  <- data.frame(month, day, year)

# obtain correct year for each date

year2=rep(NA, nrow(DDD4))
year2[1] = initial.year

for(i in 2:length(year2)) { 

    if(DDD4[i,1] <  DDD4[(i-1),1]) (year2[i] = year2[(i-1)]+1)
    if(DDD4[i,1] >= DDD4[(i-1),1]) (year2[i] = year2[(i-1)])

}

# create new dates using correct year

day2 <- sprintf("%02d", day)
month2 <- sprintf("%02d", month)
year2 <- as.character(year2)

DDD5 <- data.frame(month2, day2, year2)
DDD6 <- paste(DDD5[,1], DDD5[,2], DDD5[,3], sep='/')
DDD7 <- as.Date(DDD6, "%m/%d/%Y")
DDD7

# [1] "2010-12-30" "2011-01-01" "2011-06-01" "2011-06-01" 
#     "2011-10-25" "2011-11-27" "2011-12-28" "2012-01-16"
#     "2012-02-17" "2012-02-17" "2012-02-17"
于 2012-12-30T07:19:53.847 に答える
0

これまでに提供されたものとは異なり、ベクトル化されたアプローチと呼ぶことができるこれを投稿しています。ifelse3 つのベクトルを作成してから選択する必要があるため、疑似ベクトル化だと思います。

 dat <- read.table(text="2011.2012
 9/7 
 11/5
 12/15
 1/5
 2/5", header=TRUE)

dat$date1 <- as.Date(dat$X2011.2012, format="%m/%d") 
dat$GT <- c(FALSE, diff(dat$date1) < 0)
startyr <- cumsum( as.numeric( substr(names(dat)[1], 2,5) ) )
dat$truedate <- paste( format(dat$date1, format="%m/%d") , 
                      dat$GT+startyr, sep="-")  
 dat
#-------------------------
  X2011.2012      date1 GT   truedate
1        9/7 2012-09-07  0 09/07-2011
2       11/5 2012-11-05  0 11/05-2011
3      12/15 2012-12-15  0 12/15-2011
4        1/5 2012-01-05  1 01/05-2012
5        2/5 2012-02-05  1 02/05-2012

最初の行をヘッダーとして読み取ることは完全に正当であると考えましたが、必要に応じてcumsumdiff.Date操作の を使用した代替手段を「ベクトル化」する必要があります。これは 2 年だけに限定されるものではなく、1 年に 1 回でも日付があれば成功するはずです。

于 2012-12-30T16:54:33.887 に答える