Доступ к имени столбца dataframe с помощью функции * apply - PullRequest
3 голосов
/ 09 марта 2012

Мне нужно сделать учебник для начинающих, используя функцию 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? ... Есть ли лучший способ сделать это с $ named column?

Я решаю свой первый вопрос с помощью ответа @DWin. Но у меня есть другая проблема, непонимание, со смешанным фреймом данных (цифра + символ):

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

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)})

Ответы [ 2 ]

9 голосов
/ 09 марта 2012

В этом случае 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

Если вы хотите использовать имена столбцов в «data», то их нужно правильно написать:1005 *

 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) отправить только необходимые столбцы, которые я проиллюстрирую:как вы передаете параметры этой функции.Использование «[» и «$» в формальном списке «выглядит неправильно».И вы должны знать, что «df» будет не кадром данных, а вектором.Поскольку это не датафрейм (или список), вы должны изменить функцию внутри, чтобы она использовала «[», а не «[[» ».Поскольку вам нужны только две координаты, пропустите только две (числовые), которые вы будете использовать.

5 голосов
/ 09 марта 2012

В качестве примечания, как правило, лучше избегать использования 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 передает один столбец данных.кадр функции.

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)  
}
...