2017-01-30 6 views
0

私は2つの日付の列を持っています。二つの例の日付は、次のとおりです。Rループを避ける方法。データフレーム内の各行に対して2つの日付間の週末を1行に数える

Date1= "2015-07-17" 
Date2="2015-07-25" 

私は自分の列(この例のコードでは5 & 7)であり、それぞれが2つの日付の間の土日の数をカウントしようとしています。私は自分のデータフレームの各行に対してこのプロセスを繰り返す必要があります。最終結果は、2つの日付列で定義された日付範囲内の土曜日と日曜日の数を表す1つの列になります。

私は1つの行のために働くためのコードを取得することができます:

sum(weekdays(seq(Date1[1,5],Date2[1,7],"days")) %in% c("Saturday",'Sunday')*1)) 

これに対する答えは3になります。しかし、私は日付1と日付2の行位置に「1」を取る場合、私が得ますこのエラー:

Error in seq.Date(Date1[, 5], Date2[, 7], "days") : 
    'from' must be of length 1 

がどのように私は行ずつ移動して、ループを使用せずに、列5および7の2つの日付の間の土日の数をリスト1のベクトルを持っているのですか?もう1つの問題は、200万行があり、ループよりも少し速いものを探していることです。

ありがとうございました!

+1

ループが、 'sapply(seq_len(nrow(日付1))、関数(I)の和(平日(配列(日付1 [I]、[5]、日付2の[次のようにDate1とDate2がdata.framesの場合は、%c( "土曜日"、 "日曜日)* 1)))'が有効になります。 – lmo

+0

これは役に立ちます。私は200万行を持っていると付け加えて、それをスピードアップする方法があるかどうか疑問に思っていました!しかし、あなたのコードはうまくいった! – Tracy

+0

[再現可能な例]を提供してください(http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) – Heroka

答えて

1

map2*の機能は、purrrパッケージの方がいい方法です。それらは2つのベクトル入力(例えば2つの日付列)を受け取り、並列に関数を適用する。彼らもかなり速いです(eg previous post)!

例を示します。 _intは、整数ベクトルを返すよう要求します。

library(purrr) 

# Example data 
d <- data.frame(
    Date1 = as.Date(c("2015-07-17", "2015-07-28", "2015-08-15")), 
    Date2 = as.Date(c("2015-07-25", "2015-08-14", "2015-08-20")) 
) 

# Wrapper function to compute number of weekend days between dates 
n_weekend_days <- function(date_1, date_2) { 
    sum(weekdays(seq(date_1, date_2, "days")) %in% c("Saturday",'Sunday')) 
} 

# Iterate row wise 
map2_int(d$Date1, d$Date2, n_weekend_days) 
#> [1] 3 4 2 

あなたが戻ってあなたの元のデータフレームに結果を追加したい場合は、dplyrパッケージからmutate()は助けることができる:

library(dplyr) 
d <- mutate(d, end_days = map2_int(Date1, Date2, n_weekend_days)) 
d 
#>  Date1  Date2 end_days 
#> 1 2015-07-17 2015-07-25  3 
#> 2 2015-07-28 2015-08-14  4 
#> 3 2015-08-15 2015-08-20  2 
+0

@Simonは完璧です。どうもありがとうございます!!!! – Tracy

+0

素晴らしい!喜んで助けてください:) –

1

をここで物事をクリーンアップするdplyrを使用するソリューションです。データフレーム内の列を直接割り当てるのは難しいことではありません。

基本的に基準日を使用して、完全な週数を(床または天井によって)計算します。次に、2つの違いを取る。コードには、開始日または終了日が土曜日または日曜日になるケースは含まれません。

# weekdays(as.Date(0,"1970-01-01")) -> "Friday" 
require(dplyr) 

startDate = as.Date(0,"1970-01-01") # this is a friday 
df <- data.frame(start = "2015-07-17", end = "2015-07-25") 
df$start <- as.Date(df$start,"", format = "%Y-%m-%d", origin="1970-01-01") 
df$end <- as.Date(df$end, format = "%Y-%m-%d","1970-01-01") 

# you can use with to define the columns directly instead of %>% 

df <- df %>% 
    mutate(originDate = startDate) %>% 
    mutate(startDayDiff = as.numeric(start-originDate), endDayDiff = as.numeric(end-originDate)) %>% 
    mutate(startWeekDiff = floor(startDayDiff/7),endWeekDiff = floor(endDayDiff/7)) %>% 
    mutate(NumSatsStart = startWeekDiff + ifelse(startDayDiff %% 7>=1,1,0), 
     NumSunsStart = startWeekDiff + ifelse(startDayDiff %% 7>=2,1,0), 
     NumSatsEnd = endWeekDiff + ifelse(endDayDiff %% 7 >= 1,1,0), 
     NumSunsEnd = endWeekDiff + ifelse(endDayDiff %% 7 >= 2,1,0) 
     ) %>% 
    mutate(NumSats = NumSatsEnd - NumSatsStart, NumSuns = NumSunsEnd - NumSunsStart) 
+0

うわ@クリス!これは全く時間がかかりませんでした。文字通り!どうもありがとうございます。 – Tracy

+0

あなたは大歓迎です! –

1

日付は、1970年1月1日(木)以降の日数です。

だから、次はちょうど包括的な数を持つように、開始日をデクリメントした後、減算、その日付2つの日付の間の土曜日または日曜日の数については

f <- function(d) {d <- as.numeric(d); r <- d %% 7; 2*(d %/% 7) + (r>=2) + (r>=3)} 

ので、土曜日または日曜日の数です。

g <- function(d1, d2) f(d2) - f(d1-1) 

これらはすべてベクトル化された関数なので、列を直接呼び出すことができます。

# Example data, as in Simon Jackson's answer 
d <- data.frame(
    Date1 = as.Date(c("2015-07-17", "2015-07-28", "2015-08-15")), 
    Date2 = as.Date(c("2015-07-25", "2015-08-14", "2015-08-20")) 
) 

さらに

within(d, end_days<-g(Date1,Date2)) 
#  Date1  Date2 end_days 
# 1 2015-07-17 2015-07-25  3 
# 2 2015-07-28 2015-08-14  4 
# 3 2015-08-15 2015-08-20  2 
関連する問題