2015-09-13 8 views
9

私はRを使用して日々の最高値と最低値を含む時系列(1951〜2013)の数を分析しています。の90パーセンタイルを超える毎日の最大値と最小温度との三つ以上の連続日の期間:条件を満たす場合に連続した行をサブセット化する方法

YEAR MONTH DAY  MAX MIN 
1985  1 1 22.8 9.4 
1985  1 2 28.6 11.7 
1985  1 3 24.7 12.2 
1985  1 4 17.2 8.0 
1985  1 5 17.9 7.6 
1985  1 6 17.7 8.1 

私は、この定義に基づいて、熱波の周波数を見つける必要がある:データは、以下の構造を有しています調査期間中のすべての日の最高気温と最低気温。

基本的に、MaxとMinの一時的な値がしきい値を超えた場合、連続した日数(3つ以上)をサブセット化したいと考えています。

HW<- subset(Mydata, Mydata$MAX >= (quantile(Mydata$MAX,.9)) & 
        Mydata$MIN >= (quantile(Mydata$MIN,.9))) 

しかし、私はどのように捕まってしまった:私は90パーセンタイル温度を超えてわずか数日に私の完全なデータセットをサブセットには、次のを試してみました

YEAR MONTH DAY  MAX  MIN 
1989  7 18 45.0 23.5 
1989  7 19 44.2 26.1 
1989  7 20 44.7 24.4 
1989  7 21 44.6 29.5 
1989  7 24 44.4 31.6 
1989  7 25 44.2 26.7 
1989  7 26 44.5 25.0 
1989  7 28 44.8 26.0 
1989  7 29 44.8 24.6 
1989  8 19 45.0 24.3 
1989  8 20 44.8 26.0 
1989  8 21 44.4 24.0 
1989  8 22 45.2 25.0 

:出力はこのようなものになるだろう条件を満たす連続した日だけをサブセット化することができます。

答えて

5

アプローチでdata.tableこれは(同じデータを使用して)@ jlhowardのアプローチと少し異なります:

library(data.table) 

setDT(df) 
df[, hotday := +(MAX>=44.5 & MIN>=24.5) 
    ][, hw.length := with(rle(hotday), rep(lengths,lengths)) 
    ][hotday == 0, hw.length := 0] 

これは、特定の熱波長のための変数の代わりにTRUE/FALSEの熱波の長さ変数(hw.length)とのデータテーブルを生成します)........

> df 
    YEAR MONTH DAY MAX MIN hotday hw.length 
1: 1989  7 18 45.0 23.5  0   0 
2: 1989  7 19 44.2 26.1  0   0 
3: 1989  7 20 44.7 24.4  0   0 
4: 1989  7 21 44.6 29.5  1   1 
5: 1989  7 22 44.4 31.6  0   0 
6: 1989  7 23 44.2 26.7  0   0 
7: 1989  7 24 44.5 25.0  1   3 
8: 1989  7 25 44.8 26.0  1   3 
9: 1989  7 26 44.8 24.6  1   3 
10: 1989  7 27 45.0 24.3  0   0 
11: 1989  7 28 44.8 26.0  1   1 
12: 1989  7 29 44.4 24.0  0   0 
13: 1989  7 30 45.2 25.0  1   1 
2

あなたの質問は、残りのすべてのデータを削除して、サブセット化されたデータセットで連続3日以上のグループを見つけることに本当に沸きます。

のは、我々はいくつかの行を維持し、他の人を削除したいの例を考えてみましょう:

dat <- data.frame(year = 1989, month=c(6, 7, 7, 7, 7, 7, 8, 8, 8, 10, 10), day=c(12, 11, 12, 13, 14, 21, 5, 6, 7, 12, 13)) 
dat 
# year month day 
# 1 1989  6 12 
# 2 1989  7 11 
# 3 1989  7 12 
# 4 1989  7 13 
# 5 1989  7 14 
# 6 1989  7 21 
# 7 1989  8 5 
# 8 1989  8 6 
# 9 1989  8 7 
# 10 1989 10 12 
# 11 1989 10 13 

私たちはすでにそのわずか数日にサブセット化しましたと仮定していますので、私は、温度データを除外しましたあなたの質問のコードを使用して90パーセンタイルを超えてください。

このデータセットでは、7月の4日間の熱波と8月の3日間の熱波があります。最初のステップは、(私は既にデータがここに日が発注されると仮定)日付オブジェクトにデータを変換し、連続した観測値の間の日数を計算するために、次のようになります。

dates <- as.Date(paste(dat$year, dat$month, dat$day, sep="-")) 
(dd <- as.numeric(difftime(tail(dates, -1), head(dates, -1), units="days"))) 
# [1] 29 1 1 1 7 15 1 1 66 1 

我々は近いです、今私達ができるので、複数の日付間隔が1日ある期間を参照してください。これらの期間は、取得したい期間です。私たちは、長さ2の実行以上を保ち、数1のランを分析するためにrle機能を使用することができます。

(valid.gap <- with(rle(dd == 1), rep(values & lengths >= 2, lengths))) 
# [1] FALSE TRUE TRUE TRUE FALSE FALSE TRUE TRUE FALSE FALSE 

最後に、我々は1のいずれかの側にあったわずか数日にデータセットをサブセットすることができます熱波の一部である日の隙間:

dat[c(FALSE, valid.gap) | c(valid.gap, FALSE),] 
# year month day 
# 2 1989  7 11 
# 3 1989  7 12 
# 4 1989  7 13 
# 5 1989  7 14 
# 7 1989  8 5 
# 8 1989  8 6 
# 9 1989  8 7 
4

私はここに何かが見つからないかもしれませんが、あらかじめサブセッティングのポイントがありません。毎日のデータがある場合は、ランレングスエンコーディングを使用することができます(rle(...)関数のドキュメントを参照)。

この例では、人工データセットを作成し、MAX> = 44.5およびMIN> = 24.5という "熱波"を定義します。その後:

# example data set 
df <- data.frame(YEAR=1989, MONTH=7, DAY=18:30, 
       MAX=c(45, 44.2, 44.7, 44.6, 44.4, 44.2, 44.5, 44.8, 44.8, 45, 44.8, 44.4, 45.2), 
       MIN=c(23.5, 26.1, 24.4, 29.5, 31.6, 26.7, 25, 26, 24.6, 24.3, 26, 24, 25)) 

r <- with(with(df, rle(MAX>=44.5 & MIN>=24.5)),rep(lengths,lengths)) 
df$heat.wave <- with(df,MAX>=44.5&MIN>=24.5) & (r>2) 
df 
# YEAR MONTH DAY MAX MIN heat.wave 
# 1 1989  7 18 45.0 23.5  FALSE 
# 2 1989  7 19 44.2 26.1  FALSE 
# 3 1989  7 20 44.7 24.4  FALSE 
# 4 1989  7 21 44.6 29.5  FALSE 
# 5 1989  7 22 44.4 31.6  FALSE 
# 6 1989  7 23 44.2 26.7  FALSE 
# 7 1989  7 24 44.5 25.0  TRUE 
# 8 1989  7 25 44.8 26.0  TRUE 
# 9 1989  7 26 44.8 24.6  TRUE 
# 10 1989  7 27 45.0 24.3  FALSE 
# 11 1989  7 28 44.8 26.0  FALSE 
# 12 1989  7 29 44.4 24.0  FALSE 
# 13 1989  7 30 45.2 25.0  FALSE 

これは、その日の熱波があった場合TRUEである列、heat.waveを作成します。あなただけHW日間抽出するために必要がある場合は、

df[df$heat.wave,] 
# YEAR MONTH DAY MAX MIN heat.wave 
# 7 1989  7 24 44.5 25.0  TRUE 
# 8 1989  7 25 44.8 26.0  TRUE 
# 9 1989  7 26 44.8 24.6  TRUE 
1

単純なアプローチではなく、完全なベクトル化を使用..

# play data 
year <- c("1960") 
month <- c(rep(1,30), rep(2,30), rep(3,30)) 
day <- rep(1:30,3) 
maxT <- round(runif(90, 20, 22),1) 
minT <- round(runif(90, 10, 12),1) 

df <- data.frame(year, month, day, maxT, minT) 

# target and tricky data... 
df[1:3, 4] <- 30 
df[1:4, 5] <- 14 
df[10:13, 4] <- 30 
df[10:11, 5] <- 14 

# limits 
df$maxTope <- df$maxT - quantile(df$maxT,0.9) 
df$minTope <- df$minT - quantile(df$minT,0.9) 

# define heat day 
df$heat <- ifelse(df$maxTope > 0 & df$minTope >0, 1, 0) 

# count heat day2 
for(i in 2:dim(df)[1]){ 
    df$count[1] <- ifelse(df$heat[1] == 1, 1, 0) 
    df$count[i] <- ifelse(df$heat[i] == 1, df$count[i-1]+1, 0) 
} 

# select last day of heat wave (and show the number of days in $count) 
df[which(df$count >= 3),] 
0

は、ここでは簡単少しソリューションです:

is_High_Temp <- ((quantile(Mydata$MAX,.9)) & 
        Mydata$MIN >= (quantile(Mydata$MIN,.9))) 
start_of_a_series <- c(T,is_High_Temp[-1] != is_High_Temp[-length(x)]) # this is the tricky part 
series_number <- cumsum(start_of_a_series) 
series_length <- ave(series_number,series_number,FUN=length()) 
is_heat_wave <- series_length >= 3 & is_High_Temp 
+0

はあなたのすべてをありがとう: – Moore

関連する問題