Когда вы конвертируете .1 или 1/10 в base 2 (двоичный), вы получаете повторяющийся шаблон после десятичной точки, точно так же, как пытаетесь представить 1/3 в базе 10. Значение не является точным, и поэтому вы можете 't делать точную математику с ней, используя обычные методы с плавающей запятой.
Вы можете просто использовать имя столбца напрямую:
df <- data.frame(A=1:10, B=2:11, C=3:12)
fun1 <- function(x, column){
max(x[,column])
}
fun1(df, "B")
fun1(df, c("B","A"))
Нет необходимости использовать substitute, eval и т. д.
Вы даже можете передать нужную функцию в качестве параметра :
fun1 <- function(x, column, fn) {
fn(x[,column])
}
fun1(df, "B", max)
В качестве альтернативы, использование [[
также работает для выбора одного столбца за раз:
df <- data.frame(A=1:10, B=2:11, C=3:12)
fun1 <- function(x, column){
max(x[[column]])
}
fun1(df, "B")
Этот ответ будет охватывать многие из тех же элементов, что и существующие ответы, но эта проблема (передающая имена столбцов для функций) возникает достаточно часто, и я хочу, чтобы там был ответ, который охватывал вещи немного более всесторонне.
Предположим, что у нас очень простой фрейм данных:
dat <- data.frame(x = 1:4,
y = 5:8)
, и мы хотели бы написать функцию, которая создает новый столбец z
, который представляет собой сумму столбцов x
и y
.
Очень распространенный камень преткновения здесь состоит в том, что естественная (но некорректная) попытка часто выглядит так:
foo <- function(df,col_name,col1,col2){
df$col_name <- df$col1 + df$col2
df
}
#Call foo() like this:
foo(dat,z,x,y)
Проблема здесь в том, что df$col1
t оценить выражение col1
. Он просто ищет столбец в df
, буквально называемый col1
. Это поведение описано в ?Extract
в разделе «Рекурсивные (похожие на список) объекты».
Самое простое и наиболее часто рекомендуемое решение - это просто переключиться с $
на [[
и передать аргументы функции как строки:
new_column1 <- function(df,col_name,col1,col2){
#Create new column col_name as sum of col1 and col2
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column1(dat,"z","x","y")
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
Это часто считается «лучшей практикой», так как это самый сложный метод. Передача имен столбцов в виде строк примерно такая же однозначная, как вы можете получить.
Следующие два варианта более продвинутые. Многие популярные пакеты используют эти методы, но использование их хорошо требует большей осторожности и умения, поскольку они могут вводить тонкие сложности и непредвиденные точки отказа. Этот раздел книги Хэдли Advanced R является отличной ссылкой для некоторых из этих проблем.
Если вы действительно хотите сохранить пользователя от ввода всех этих кавычки, одним из вариантов может быть преобразование голой, некотируемых имен столбцов в строки с помощью deparse(substitute())
:
new_column2 <- function(df,col_name,col1,col2){
col_name <- deparse(substitute(col_name))
col1 <- deparse(substitute(col1))
col2 <- deparse(substitute(col2))
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column2(dat,z,x,y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
Это, откровенно говоря, немного глупо, возможно, так как мы действительно делаем то же самое, что и в new_column1
, просто с кучей дополнительной работы, чтобы преобразовать простые имена в строки.
Наконец, если мы хотим получить действительно фантазию, мы можем решить, что вместо того, чтобы проходить в именах добавляемых двух столбцов мы хотели бы быть более гибкими и допускать другие комбинации двух переменных. В этом случае мы, скорее всего, прибегнем к использованию eval()
в выражении, включающем два столбца:
new_column3 <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[[col_name]] <- eval(substitute(expr),df,parent.frame())
df
}
Просто для удовольствия я все еще использую deparse(substitute())
для имени нового столбца , Здесь будет работать все следующее:
> new_column3(dat,z,x+y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
> new_column3(dat,z,x-y)
x y z
1 1 5 -4
2 2 6 -4
3 3 7 -4
4 4 8 -4
> new_column3(dat,z,x*y)
x y z
1 1 5 5
2 2 6 12
3 3 7 21
4 4 8 32
Итак, короткий ответ в основном: передать имена столбцов data.frame в виде строк и использовать [[
для выбора отдельных столбцов. Только начинайте разбираться в eval
, substitute
и т. Д., Если вы действительно знаете, что делаете.
Лично я считаю, что передача столбца в виде строки довольно уродливая. Мне нравится делать что-то вроде:
get.max <- function(column,data=NULL){
column<-eval(substitute(column),data, parent.frame())
max(column)
}
, которое даст:
> get.max(mpg,mtcars)
[1] 33.9
> get.max(c(1,2,3,4,5))
[1] 5
Обратите внимание, что спецификация data.frame является необязательной. вы можете даже работать с функциями ваших столбцов:
> get.max(1/mpg,mtcars)
[1] 0.09615385