#r #function #if-statement
#r #функция #if-оператор
Вопрос:
Я пытаюсь использовать инструкции ifelse в R, чтобы добавить определенный префикс к моим фреймам данных.
На данный момент у меня две проблемы с моим кодом.
1) Когда я пытаюсь обернуть это в функцию, она не возвращает отредактированные фреймы данных.
2) параметр no = инструкции ifelse, которую я ввел, повторяется, как мне заставить это повторяться только один раз?
Был бы признателен за любую помощь.
примечание. В этом примере я использую некоторые выдуманные данные по профессиональным причинам.
dput(head(Player1)):
structure(list(Class = structure(c(2L, 1L, 5L, 4L, 3L), .Label = c("fighter",
"paladin", "rouge", "sorceror", "wizard"), class = "factor"),
Race = structure(c(3L, 1L, 4L, 3L, 2L), .Label = c("elf",
"gnome", "human", "orc"), class = "factor"), alignment = structure(c(4L,
2L, 1L, 5L, 3L), .Label = c("CE", "CG", "LG", "NE", "NN"), class = "factor"),
Level = c(6, 7, 1, 2, 4)), row.names = c(NA, 5L), class = "data.frame")
dput(head(Player2)):
structure(list(Class = structure(c(2L, 1L, 5L, 4L, 3L), .Label = c("fighter",
"paladin", "rouge", "sorceror", "wizard"), class = "factor"),
Race = structure(c(3L, 1L, 4L, 3L, 2L), .Label = c("elf",
"gnome", "human", "orc"), class = "factor"), alignment = structure(c(4L,
2L, 1L, 5L, 3L), .Label = c("CE", "CG", "LG", "NE", "NN"), class = "factor"),
Level = c(6, 7, 1, 2, 4)), row.names = c(NA, 5L), class = "data.frame")
Допустим, у нас есть два игрока, Джон (игрок1) и Люси (игрок2), и мы хотим добавить префикс к их именам. Я добился этого, используя приведенный ниже код.
ifelse(test = grepl('Johns', names(Player1)) == F,
yes = colnames(Player1) <- paste('Johns', colnames(Player1), sep = '_'),
no = print('Player info is fine'))
Вывод здесь работает, и все столбцы получают ‘Johns_’ в качестве префикса
Однако, когда я пытаюсь преобразовать это в функцию для обоих проигрывателей фреймов данных, изменений не происходит.
Функция:
Addnames <- function(Player1, Player2){
ifelse(test = grepl('Johns', names(Player1)) == F,
yes = colnames(Player1) <- paste('Johns', colnames(Player1), sep = '_'),
no = print('Player info is fine'))
ifelse(test = grepl('Lucys', names(Player2)) == F,
yes = colnames(Player2) <- paste('Lucys', colnames(Player2), sep = '_'),
no = print('Player info is fine'))
return(Player1)
return(Player2)
}
Addnames(Player1, Player2)
Это не изменяет имена столбцов фреймов данных.
Мой идеальный результат — иметь ‘Johns_’ и ‘Lucys_’ в качестве префикса к имени каждого столбца для фреймов данных Player1 и Player2 соответственно.
Я хотел бы сделать это в функции.
Другая проблема, с которой я сталкиваюсь, заключается в инструкции ifelse, если no = ‘Информация об игроке в порядке’ повторяется для каждого имени столбца. Как мне заставить это повторяться только один раз.
Опять же, любая помощь была бы высоко оценена.
Комментарии:
1. Ваша первая проблема заключается в том, что функция не может изменять объекты в глобальной среде (вне функции), если вы либо специально не укажете ей это, либо не присвоите выходные данные функции переменной в глобальной среде. Ваша вторая проблема заключается в том, что первый
return()
вызов завершает работу функции, поэтому у вас не может быть двух отдельныхreturn()
вызовов в функции.2. Я не уверен, но вы хотите изменить имена столбцов для обоих фреймов данных? Вам нужно
names(Player1) <- paste0("Johns_", names(Player1)); names(Player2) <- paste0("Lucys_", names(Player2))
?3. Хммм … в вашем точном воспроизводимом сообщении действительно отображаются столбцы первого фрейма данных, которые изменены. Смотрите демонстрацию: rextester.com/DYV6690 . Просто отрегулируйте возврат для обоих фреймов данных:
return(list(Player1, Player2)
.4. @Parfait но не то, чтобы это возвращало единый список с двумя элементами, один для Player1 и один для Player2. Вы не можете напрямую назначить этот результат двум фреймам данных. (Я уверен, вы это знаете, просто хотел предупредить операционную систему).
5. @iod … OP должен работать со списками фреймов данных, особенно если они аналогично структурированы! Избегайте затопления глобальной среды отдельными подобными объектами.
Ответ №1:
Предполагая, что у вас больше, чем просто два проигрывателя, вам, вероятно, понадобится функция многократного использования. Аналогично вышеупомянутому решению от fmarm, но перерабатывает большую часть вашего исходного кода:
Addnames <- function(player, namestring){
ifelse(test = grepl(namestring, names(player)) == F,
yes = colnames(player) <- paste(namestring, colnames(player), sep = '_'),
no = print('Player info is fine'))
return(player)
}
Player1 <- Addnames(player=Player1, namestring="Johns")
Player2 <- Addnames(player=Player2, namestring="Lucys")
Редактировать: далее, предполагая, что «Lucys» на самом деле называется «Lucy», добавление «s», конечно, также может быть выполнено внутри функции:
Addnames <- function(player, namestring){
ifelse(test = grepl(namestring, names(player)) == F,
yes = colnames(player) <- paste(namestring, "s", colnames(player), sep = '_'),
no = print('Player info is fine'))
return(player)
}
Player1 <- Addnames(player=Player1, namestring="John")
Player2 <- Addnames(player=Player2, namestring="Lucy")
Ответ №2:
Если вы действительно хотите сделать это в функции, я бы предпочел создать функцию, которая принимает два аргумента: имя фрейма данных и имя проигрывателя, так что можно возвращать только одно: фрейм данных с правильными именами столбцов
Addnames <- function(player_df,player_name){
column_names_to_change <- which(!grepl('Johns', names(player_df)))
colnames(player_df)[column_names_to_change] <- paste(player_name,colnames(player_df)[column_names_to_change],sep="_")
return(player_df)
}
Чтобы изменить фрейм данных после функции, вам нужно переназначить результат обратно в Player1
Player1 <- Addnames(Player1,"Johns")
Player2 <- Addnames(Player2,"Lucys")
Ответ №3:
Просто используйте списки и run Map
для поэлементного перебора между проигрывателями и соответствующими фреймами данных без какой-либо ifelse
условной логики. Даже используйте setNames
для возврата функции с правой стороны.
player_list <- c("John", "Lucy")
df_list <- list(Player1, Player2)
# RENAME COLUMNS ELEMENTWISE
new_df_list <- Map(function(nm, df) setNames(df, paste0(nm, "_", colnames(df))),
player_list, df_list)
# OUTPUT DF ELEMENTS
new_df_list$John
# John_Class John_Race John_alignment John_Level
# 1 paladin human NE 6
# 2 fighter elf CG 7
# 3 wizard orc CE 1
# 4 sorceror human NN 2
# 5 rouge gnome LG 4
new_df_list$Lucy
# Lucy_Class Lucy_Race Lucy_alignment Lucy_Level
# 1 paladin human NE 6
# 2 fighter elf CG 7
# 3 wizard orc CE 1
# 4 sorceror human NN 2
# 5 rouge gnome LG 4