使用*apply函数访问数据框的列名称

问题描述 投票:0回答:3

我需要为初学者使用 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)})
r transform dataframe lapply
3个回答
11
投票

在这种情况下,

apply
就是您所需要的。所有数据列都属于同一类型,您不必担心丢失属性,而这正是 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”不会是一个数据帧,而是一个向量。因为它不是数据框(或列表),所以您应该更改内部函数,以便它使用“[”而不是“[[”。由于您只需要两个坐标,因此只需传递您将使用的两个(数字)坐标。


6
投票

作为旁注,一般来说,最好避免使用

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

0
投票

对于后来遇到这个话题的人。按名称访问列的更好解决方案是使用

lapply()
。就像下面这样:

lapply(1, function(i, df) { fDist2(df[1,]$X1,df[1,]$Y1,df)}, df=data2)[[1]]

lapply()
中,i 是必须有的,然后只需将数据帧
data2
作为附加参数传递,然后您就可以在 function(){} 内使用
df$any_column_you_want
引用任何列。

© www.soinside.com 2019 - 2024. All rights reserved.