0

これまでに対処したことがある場合は事前にお詫びしますが、ddply、sapply、applyに関連するすべての質問を調べてみましたが、これを理解することはできません...

課金サイクルの日、月、合計日数を引数として取り、課金サイクルが含まれていた暦月数を返す関数countMonthsを作成しました。

countMonths <- function(day, month, cycle.days) {
  month.days <- c(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
  if (month < 1 | month > 12 | floor(month) != month) {
    cat("Invalid month value, must be an integer from 1 to 12")
  } else if (day < 1 | day > month.days[month]) {
    cat("Invalid day value, must be between 1 and month.days[month]")
  } else if (cycle.days < 0) {
    cat("Invalid cycle.days value, must be >= 0")
  } else {
    nmonths <- 1
    day.ct <- cycle.days - day
    while (day.ct > 0) {
      nmonths <- nmonths + 1
      month <- ifelse(month == 1, 12, month - 1) # sets to previous month    
      day.ct  <- day.ct - month.days[month] # subtracts days of previous month
    }
    nmonths
  }
}

この関数を、顧客ごとの請求レコードを含むdata.frameのすべての行に適用したいと思います。

> head(cons2[-1],10)
   kwh cycle.days  read.date row.index year month day kwh.per.day
1  381         29 2010-09-02         1 2010     9   2   13.137931
2  280         32 2010-10-04         2 2010    10   4    8.750000
3  282         29 2010-11-02         3 2010    11   2    9.724138
4  330         34 2010-12-06         4 2010    12   6    9.705882
5  371         30 2011-01-05         5 2011     1   5   12.366667
6  405         30 2011-02-04         6 2011     2   4   13.500000
7  441         32 2011-03-08         7 2011     3   8   13.781250
8  290         29 2011-04-06         8 2011     4   6   10.000000
9  296         29 2011-05-05         9 2011     5   5   10.206897
10 378         32 2011-06-06        10 2011     6   6   11.812500

> dput(head(cons2[-1],10))
structure(list(kwh = c(381L, 280L, 282L, 330L, 371L, 405L, 441L, 
290L, 296L, 378L), cycle.days = c(29L, 32L, 29L, 34L, 30L, 30L, 
32L, 29L, 29L, 32L), read.date = structure(c(1283385600, 1286150400, 
1288656000, 1291593600, 1294185600, 1296777600, 1299542400, 1302048000, 
1304553600, 1307318400), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    row.index = 1:10, year = c(2010, 2010, 2010, 2010, 2011, 
    2011, 2011, 2011, 2011, 2011), month = c(9, 10, 11, 12, 1, 
    2, 3, 4, 5, 6), day = c(2L, 4L, 2L, 6L, 5L, 4L, 8L, 6L, 5L, 
    6L), kwh.per.day = c(13.1379310344828, 8.75, 9.72413793103448, 
    9.70588235294118, 12.3666666666667, 13.5, 13.78125, 10, 10.2068965517241, 
    11.8125)), .Names = c("kwh", "cycle.days", "read.date", "row.index", 
"year", "month", "day", "kwh.per.day"), row.names = c(NA, 10L
), class = "data.frame")

私はいくつかのオプションを試しましたが、どれもうまくいきません。具体的には、特定の変数の値をデータフレームの各行のスカラー(または長さ1のベクトル)として渡すことができる必要がありますが、それらは常にベクトルとして渡されます。

> cons2$tot.months <- countMonths(cons2$day, cons2$month, cons2$cycle.days)  
Warning messages:
1: In if (month < 1 | month > 12 | floor(month) != month) { :
  the condition has length > 1 and only the first element will be used
2: In if (day < 1 | day > month.days[month]) { :
  the condition has length > 1 and only the first element will be used
3: In if (cycle.days < 0) { :
  the condition has length > 1 and only the first element will be used
4: In while (day.ct > 0) { :
  the condition has length > 1 and only the first element will be used
5: In while (day.ct > 0) { :
  the condition has length > 1 and only the first element will be used

私はついにddplyを使用して正しい結果を得ることができ、各行を独自のグループとして扱いましたが、長い時間がかかります。

cons2 <- ddply(cons2, .(account, year, month, day), transform,
               tot.months = countMonths(day, month, cycle.days)
)

この関数をデータフレームの各行に適用するためのより良い方法はありますか?または、関連する質問として、データフレーム内のその変数のすべての値のベクトルではなく、スカラー引数(特定の行からの値)としてデータフレームから変数を渡すにはどうすればよいですか?私の考えのどこが間違っているのか、誰かが指摘してくれたら特にありがたいです。

4

1 に答える 1

1

関数を機能させるには、関数を使用mapplyして、渡されるすべてのベクトルの各要素に関数を連続して適用します。だからあなたはすることができます:

mapply(countMonths,cons2$day,cons2$month,cons2$cycle.days)

コメントで述べたように、これを行うためのより簡単な方法があります。たとえば、これはうまくいくと思います。

cons2$read.date=as.Date(cons2$read.date)
monnb <- function(d){ lt <- as.POSIXlt(as.Date(d, origin="1900-01-01"));  lt$year*12 + lt$mon }
mondf <- function(d1, d2)  monnb(d2) - monnb(d1) 
mondf(cons2$read.date-cons2$cycle.days,cons2$read.date) + 1

また、関数が機能しないすべての条件をキャッチしようとしていることに気づきました。これはすばらしいことです。stopifnotこの目的に役立つと呼ばれる非常に便利な関数があります。

countMonths <- function(day, month, cycle.days) {
  month.days <- c(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
  stopifnot(month >=1 & month <= 12 & floor(month)==month & cycle.days >=0 & day >= 1 & day <= month.days[month]) 
  nmonths <- 1
  day.ct <- cycle.days - day
  while (day.ct > 0) {
    nmonths <- nmonths + 1
    month <- ifelse(month == 1, 12, month - 1) # sets to previous month    
    day.ct  <- day.ct - month.days[month] # subtracts days of previous month
  }
  nmonths
}

関数に関するコメントについては、機能すると思いますが、Rのベクトル演算を利用していません。他の回答から得た関数は、日付のベクトル全体をでフィードできるため、非常に洗練されています。それぞれを連続してループするのではなく、1回。

于 2012-09-27T20:58:23.223 に答える