Попытка применить функцию по строкам к фрейму данных, чтобы создать новый столбец - PullRequest
0 голосов
/ 30 марта 2019

У меня есть датафрейм услуг бронирования. Каждое бронирование имеет дату начала и окончания контракта. На определенную отчетную дату я хочу определить, активен ли контракт и, если да, то, сколько нужно выставить счет на основе ежемесячной ставки выставления счетов. Если контракт заканчивается в середине месяца, я выставляю счет на последний месяц. Вот кадр данных:

> bookings
     Account Service  MonthlyRate ContractStart ContractEnd
     1 A       W              50 2018-01-01    2018-12-31 
     2 A       X              75 2018-03-15    2019-03-14 
     3 B       W              60 2018-02-28    2018-09-30 
     4 B       X              90 2018-05-12    2019-08-11 
     5 B       Y              45 2018-02-28    2018-09-30 
     6 C       Y              50 2018-07-31    2019-04-30 
     7 D       W              65 2019-01-01    2019-03-31 
     8 D       Y              50 2018-09-01    2019-05-31 
     9 D       Z             110 2018-08-22    2019-12-31 
    10 E       Z             100 2018-10-01    2019-09-30 

Я написал функцию, использующую lubridate для расчета ежемесячного выставления счетов.

    monthly_revenue <- function(reporting_date, monthly_rate, start, end) {
      contract_int <- interval(start, end) # Contract interval
      # Calculate interval ending the last day of the month of contract end
      end_of_month <- end
      day(end_of_month) <- days_in_month(end)
      end_of_month_int <- interval(start, end_of_month)
      # Check if reporting date is within contract interval
      if(reporting_date %within% contract_int) {
        val <- 1 # bill for entire month
        # If not within interval, check if contract is in its last month
      } else if (reporting_date %within% end_of_month_int) {
        val <- day(end) / days_in_month(end) # prorate monthly charges
      } else { # Not within contract
        val <- 0 # zero revenue
      }
      val * monthly_rate
    }

Затем я устанавливаю дату выставления счета и применяю функцию по очереди к фрейму данных:

    billing_date <- as.Date("2019-03-29")
    revenue_for_month <-bookings %>%
      rowwise() %>%
      mutate(Revenue = monthly_revenue(billing_date, MonthlyRate, ContractStart, ContractEnd))

Что приводит к следующей ошибке:

   Error in mutate_impl(.data, dots) : 
      Evaluation error: non-numeric argument to binary operator.

Я не могу сказать, связана ли проблема с моей функцией или как я выполняю итерации. Любая помощь будет с благодарностью.

[продолжение на основе полученных комментариев] Я использую следующие вызовы библиотеки:

library(tidyverse)
library(lubridate)

А вот вывод dput для моего кадра данных:

> dput(bookings)
structure(list(Account = c("A", "A", "B", "B", "B", "C", "D", 
"D", "D", "E"), Type = c("W", "X", "W", "X", "Y", "Y", "W", "Y", 
"Z", "Z"), MonthlyRate = c(50L, 75L, 60L, 90L, 45L, 50L, 65L, 
50L, 110L, 100L), ContractStart = structure(c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, 
NA_real_), class = "Date"), ContractEnd = structure(c(NA_real_, 
NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, 
NA_real_, NA_real_), class = "Date")), .Names = c("Account", 
"Type", "MonthlyRate", "ContractStart", "ContractEnd"), row.names = c(NA, 
-10L), spec = structure(list(cols = structure(list(Account = structure(list(), class = c("collector_character", 
"collector")), Type = structure(list(), class = c("collector_character", 
"collector")), MonthlyRate = structure(list(), class = c("collector_integer", 
"collector")), ContractStart = structure(list(), class = c("collector_character", 
"collector")), ContractEnd = structure(list(), class = c("collector_character", 
"collector"))), .Names = c("Account", "Type", "MonthlyRate", 
"ContractStart", "ContractEnd")), default = structure(list(), class = c("collector_guess", 
"collector"))), .Names = c("cols", "default"), class = "col_spec"), class = c("tbl_df", 
"tbl", "data.frame"))

1 Ответ

0 голосов
/ 30 марта 2019

Я немного изменил вашу функцию, потому что столкнулся с многочисленными проблемами.Теперь это работает для меня:

monthly_revenue <- function(reporting_date, monthly_rate, start, end) {
  contract_int <- interval(start, end) # Contract interval
  EoM_int <- interval(start, ceiling_date(as_date(end),unit="month")-1)

  reporting_date <- as_datetime(reporting_date)

  if(reporting_date %within% contract_int) {
    val <- 1 # bill for entire month
    # If not within interval, check if contract is in its last month
  } else if (reporting_date %within% EoM_int) {
    val <- day(end) / day(ceiling_date(as_date(end),unit="month")-1) # prorate monthly charges
  } else { # Not within contract
    val <- 0 # zero revenue
  }
  return(val * monthly_rate)
}

Ваш код dplyr правильный и работает нормально.

...