Доступ к имени столбца фрейма данных с помощью функции *apply
Вопрос
Мне нужно сделать учебник для начинающих, используя функцию R *apply (без использования пакета reshape или plyr в первый раз)
Я стараюсь lapply
(потому что я читаю apply
не подходит для фрейма данных) простая функция для этого фрейма данных, и я хочу использовать именованный столбец для доступа к данным:
fDist <- function(x1,x2,y1,y2) {
return (0.1*((x1 - x2)^2 + (y1-y2)^2)^0.5)
}
data <- read.table(textConnection("X1 Y1 X2 Y2
1 3.5 2.1 4.1 2.9
2 3.1 1.2 0.8 4.3
"))
data$dist <- lapply(data,function(df) {fDist(df$X1 , df$X2 , df$Y1 , df$Y2)})
у меня есть эта ошибка $ operator is invalid for atomic vectors
, вероятно, это связано с тем, что фрейм данных изменяется с помощью laply?...есть ли лучший способ сделать это с помощью именованного столбца $?
Я решаю свой первый вопрос с помощью ответа @DWin.Но у меня есть еще одна проблема, недоразумение, со смешанным фреймом данных (число + символ):
В моем новом варианте использования я использую две функции для вычисления расстояния, потому что моя цель — сравнить точку расстояния между всеми другими точками.
data2 <- read.table(textConnection("X1 Y1 X2 Y2
1 3.5 2.1 4.1 2.9
2 3.1 1.2 0.8 4.3
"))
data2$char <- c("a","b")
fDist <- function(x1,y1,x2,y2) {
return (0.1*((x1 - x2)^2 + (y1-y2)^2)^0.5)
}
fDist2 <- function(fixedX,fixedY,vec) {
fDist(fixedX,fixedY,vec[['X2']],vec[['Y2']])
}
# works with data (dataframe without character), but not with data2 (dataframe with character)
#ok
data$f_dist <- apply(data, 1, function(df) {fDist2(data[1,]$X1,data[1,]$Y1,df)})
#not ok
data2$f_dist <- apply(data2, 1, function(df) {fDist2(data2[1,]$X1,data2[1,]$Y1,df)})
Решение
В этом случае apply
это то, что вам нужно.Все столбцы данных имеют один и тот же тип, и вам не нужно беспокоиться о потере атрибутов, в которых применение вызывает проблемы.Вам нужно будет написать свою функцию по-другому, чтобы она занимала один вектор длины 4:
fDist <- function(vec) {
return (0.1*((vec[1] - vec[2])^2 + (vec[3]-vec[4])^2)^0.5)
}
data$f_dist <- apply(data, 1, fDist)
data
X1 Y1 X2 Y2 f_dist
1 3.5 2.1 4.1 2.9 0.1843909
2 3.1 1.2 0.8 4.3 0.3982462
Если вы хотите использовать имена столбцов в «данных», их необходимо написать правильно:
fDist <- function(vec) {
return (0.1*((vec['X1'] - vec['X2'])^2 + (vec['Y1']-vec['Y2'])^2)^0.5)
}
data$f_dist <- apply(data, 1, fDist)
data
#--------
X1 Y1 X2 Y2 f_dist
1 3.5 2.1 4.1 2.9 0.1000000
2 3.1 1.2 0.8 4.3 0.3860052
Ваш обновленный (и совсем другой) вопрос легко решить.Когда вы используете apply
он приводит к наименьшему знаменателю общего режима, в данном случае к «символу».У вас есть два варианта:либо 1) добавить as.numeric
ко всем вашим аргументам внутри функций или 2) отправлять только необходимые столбцы, которые я проиллюстрирую:
data2$f_dist <- apply(data2[ , c("X2", "Y2") ], 1, function(coords)
{fDist2(data2[1,]$X1,data2[1,]$Y1, coords)} )
Мне очень не нравится, как вы передаете параметры этой функции.Использование «[» и «$» в списке формалов «выглядит неправильно». И вы должны знать, что «DF» не будет не кафедом данных, а скорее вектором.Поскольку это не кадр данных (или список), вам следует изменить внутреннюю функцию так, чтобы она использовала «[», а не «[[».Поскольку вам нужны только две координаты, передайте только те две (числовые), которые вы будете использовать.
Другие советы
В качестве примечания, как правило, лучше избегать использования data
в качестве имени переменной, поскольку это функция в базе R:
dat <- read.table(textConnection("X1 Y1 X2 Y2
1 3.5 2.1 4.1 2.9
2 3.1 1.2 0.8 4.3
"))
lapply
передает один столбец data.frame в функцию.
lapply(dat, function(df) print(df))
Вместо этого вы хотите apply
.Но он передает одну строку как вектор, который не использует $
оператор.Вместо этого вы можете индексировать напрямую:
apply(dat, 1, function(vec) {fDist(vec[1] , vec[3] , vec[2] , vec[4])})
Или перепишите функцию, чтобы она принимала позиционные аргументы в качестве дополнительных аргументов.
fDist <- function(vec, pos1, pos2, pos3, pos4) {
return (0.1*((vec[pos1] - vec[pos2])^2 + (vec[pos3]-vec[pos4])^2)^0.5)
}
apply(dat, 1, fDist, pos1=1, pos2=3, pos3 = 2, pos4=4)
Однако лучшим решением было бы полностью векторизовать вашу функцию:
fDist <- function(df) {
return (0.1*((df$X1 - df$X2)^2 + (df$Y1-df$Y2)^2)^0.5)
}