将函数应用于data.frame会生成NAs,同时将其应用于列工作

时间:2015-12-14 19:59:09

标签: r dataframe apply numeric factors

我想将权重应用于R中的数据框,该数据框由数字和因子的变量组成。当我创建一个将因子转换为数字然后对变量进行加权并将其应用于任何给定列的函数时,它运行良好。但是,当我使用apply函数将其应用于data.frame时,它会生成NA。例如:

set.seed(123)
frame <- data.frame(x = sample(1:100,10), y = c(rep("1",5), rep("2",5)))

weights <- 10
weight.fun <- function(x){
    x <- if(class(x) == "numeric" | class(x) == "integer"){x} else {as.numeric(levels(x))[x]}
    x*weights
}

weight.fun(frame$x)
# [1] 290 790 410 860 910  50 500 830 510 420
weight.fun(frame$y)
# [1] 10 10 10 10 10 20 20 20 20 20
apply(frame,2,weight.fun)
#        x  y
#  [1,] NA NA
#  [2,] NA NA
#  [3,] NA NA
#  [4,] NA NA
#  [5,] NA NA
#  [6,] NA NA
#  [7,] NA NA
#  [8,] NA NA
#  [9,] NA NA
# [10,] NA NA

有关为何会发生这种情况的任何想法吗?

2 个答案:

答案 0 :(得分:4)

如果您使用sapply代替apply,操作将按预期运行:

sapply(frame, weight.fun)
#         x  y
#  [1,] 290 10
#  [2,] 790 10
#  [3,] 410 10
#  [4,] 860 10
#  [5,] 910 10
#  [6,]  50 20
#  [7,] 500 20
#  [8,] 830 20
#  [9,] 510 20
# [10,] 420 20

这种差异的原因是apply对矩阵(或数组)进行操作。来自?apply

  

返回通过应用a获得的向量或数组或值列表   函数到数组或矩阵的边距。

因此,在使用frame时,您的数据框apply将转换为矩阵,这意味着所有列的数据类型将被强制相同(在您的情况下为字符串):

as.matrix(frame)
#        x    y  
#  [1,] "29" "1"
#  [2,] "79" "1"
#  [3,] "41" "1"
#  [4,] "86" "1"
#  [5,] "91" "1"
#  [6,] " 5" "2"
#  [7,] "50" "2"
#  [8,] "83" "2"
#  [9,] "51" "2"
# [10,] "42" "2"

这解释了apply的意外行为 - weight.fun正在传递字符向量。

同时,sapply对列表进行操作,这正是您想要的,因为数据帧是列表。使用sapply,每个列的类型都保留在数据框中,因此首先使用整数向量调用weight.fun,然后使用因子调用它。

答案 1 :(得分:0)

看起来问题出在你的职能部门。你的if语句是返回NA的,所以这不是一个应用问题,如果x是一个字符,它将失败。编写这样的函数似乎适用于apply。

set.seed(123)
frame <- data.frame(x = sample(1:100,10), y = c(rep("1",5), rep("2",5)))

weight.fun <- function(x, w = 10){ 
  if(!class(x) == "numeric" & !class(x) == "integer") {
    if(class(x) == "factor") { x <- as.numeric(as.character(x)) }
    else if(class(x) == "character") { x <- as.numeric(x) }  
  } 
  return(x * w)
}

apply(frame, MARGIN = 2, FUN = weight.fun)