Правильное построение функции в R
Я пишу свою первую функцию когда-либо (включая любой другой язык программирования), и я немного запутался в правильной структуре для if
, else
и ifelse
. Я искал массу примеров, но мне все это не ясно.
Ситуация. Я пытаюсь подсказать клиентам, как долго они были клиентами, а затем превратить это в фактор.
#Sample Data
clientID <- round(runif(2,min=2000, max=3000),0)
MonthsSinceSignUp <- round(runif(20,min=1, max=60),0)
df <- data.frame(cbind(clientID,MonthsSinceSignUp))
Для данного клиента я хотел бы определить, были ли они так меньше года, больше года, но менее 2 и т.д.
Это моя первая трещина в функции:
ClientAgeRange <- function(MonthsSinceSignUp) {
if (MonthsSinceSignUp < 13) {ClientAgeRange <- '1 year'}
} else {
if (MonthsSinceSignUp > 13 & MonthsSinceSignUps < 25) {ClientAgeRange <- '2 years'}
} else {ClientAgeRage <- '3+ years'}
Ошибка, которую я продолжаю получать:
Error: unexpected '}' in "}"
, что указывает на то, что я отсутствует или у вас есть дополнительная закрывающая скобка. Однако, несмотря на мою проблему, я не могу ее найти. Но - я думаю, в общем, я не применяю правильную структуру к функции. Я пытаюсь создать if this, then set this variable as that
. Как я могу правильно структурировать эту функцию?
Наконец - если бы я хотел добавить вывод функции в dataframe
, это apply
правильный способ сделать это?
Ответы
Ответ 1
Ответ в двух частях:
Совет:
Мой первый совет - использовать редактор кода, который выполняет сопоставление скобок. Например, в Notepad++
вы получите следующее:
PS. Я не рекомендую Notepad++
- вместо этого использовать Rstudio - я просто использую Notepad++
из-за ярких (и, следовательно, легко различимых) цветов
![enter image description here]()
Обратите внимание, что выделенная фигурная скобка (в красном) соответствует скобке в середине вашей функции. Это показывает, что в конце вашего первого if
есть избыточная скобка. Итак, сначала исправьте это:
![enter image description here]()
ОК, теперь нет подходящей фигурной скобки (не выделено красным), поэтому вам нужно добавить отсутствующую скобку в конце вашей функции:
![enter image description here]()
Исправление:
Но вы можете значительно упростить свою функцию, если используете cut
, который предназначен для этого типа анализа:
ClientAgeRange <- function(x) {
cut(x, breaks=c(0, 13, 25, Inf), labels=c("1 year", "2 years", "3+ years"))
}
Попробуйте в своем коде:
ClientAgeRange(df$MonthsSinceSignUp)
[1] 2 years 1 year 3+ years 2 years 3+ years 3+ years 2 years 2 years 3+ years 3+ years 1 year
[12] 3+ years 2 years 3+ years 3+ years 3+ years 3+ years 3+ years 3+ years 3+ years
Levels: 1 year 2 years 3+ years
Ответ 2
if (MonthsSinceSignUp < 13) {ClientAgeRange <- '1 year'}
}
У вас есть дополнительный} здесь.
Как правило, рекомендуется принять соглашения для форматирования вашего кода. Одна из конвенций, которую я очень рекомендую, всегда ставит тело "блока" (здесь я использую блок как общий термин для "stuff inside {}", который включает тела функций, если инструкции и циклы) на своей собственной строке, как показано ниже:
ClientAgeRange <- function(MonthsSinceSignUp) {
if (MonthsSinceSignUp < 13) {
ClientAgeRange <- '1 year'
} else if (MonthsSinceSignUp > 13 & MonthsSinceSignUps < 25) {
ClientAgeRange <- '2 years'
} else {
ClientAgeRage <- '3+ years'
}
}
Посмотрите, как все это становится понятным?
Что касается вашего второго вопроса, функция без побочных эффектов принимает ввод, делает материал и возвращает выход. Сейчас у вас нет никакого возвращаемого значения, и из ваших соглашений об именах кажется, что вы немного смущены.
Попробуйте следующее:
ClientAgeRange <- function(MonthsSinceSignUp) {
if (MonthsSinceSignUp < 13) {
result <- '1 year'
} else if (MonthsSinceSignUp > 13 & MonthsSinceSignUps < 25) {
result <- '2 years'
} else {
result <- '3+ years'
}
return(result)
}
return(
является необязательным в R, но это поможет вам более четко продумать функции.
Ответ 3
Попробуйте следующее (обратите внимание, что я использовал else if
, чтобы упростить его):
ClientAgeRange <- function(MonthsSinceSignUp) {
if (MonthsSinceSignUp < 13) {
ClientAgeRange <- '1 year'
} else if (MonthsSinceSignUp > 13 & MonthsSinceSignUp < 25) {
ClientAgeRange <- '2 years'
} else {ClientAgeRage <- '3+ years'}
}
Затем вы можете добавить его в свой файл данных следующим образом:
df$ClientAgeRange <- sapply(MonthsSinceSignUp, ClientAgeRange)
Как вы сказали, примените (я использовал sapply в этом случае, есть несколько мест, которые вы можете прочитать, чтобы прочитать о разных прикладных функциях, например здесь) это правильный путь. Это связано с тем, что мы не можем просто передать весь вектор в функцию; он требует, чтобы отдельные элементы выполняли необходимые сравнения.