在下文中,逻辑运算符似乎无法正常工作。
a = c(TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)
b = c('a', 'b', 'c', 'de', 'f', 'g')
c = c(1, 2, 3, 4, 5, 6)
d = c(0, 0, 0, 0, 0, 1)
wtf = data.frame(a, b, c, d)
wtf$huh = apply(wtf, 1, function(row) {
if (row['a'] == T) { return('we win') }
if (row['c'] < 5) { return('hooray') }
if (row['d'] == 1) { return('a thing') }
return('huh?')
})
产:
> wtf
a b c d huh
1 TRUE a 1 0 hooray
2 FALSE b 2 0 hooray
3 TRUE c 3 0 hooray
4 FALSE de 4 0 hooray
5 TRUE f 5 0 huh?
6 TRUE g 6 1 a thing
天真地想要在第1,3,5和6行中,会有we win
。
有人可以向我解释(1)为什么会这样做,(2)如何修复它以使其不会发生,(3)为什么我的所有逻辑列似乎都被改为字符,以及(4)如何将函数类型安全地应用于数据框中的行?
答案 0 :(得分:7)
为什么会这样?因为apply
是为矩阵而制作的。当你给它一个数据框时,发生的第一件事是它被转换为矩阵:
m = as.matrix(wtf)
m
# a b huh huh1
# [1,] " TRUE" "a" "huh?" "hooray"
# [2,] "FALSE" "b" "huh?" "huh?"
# [3,] " TRUE" "c" "huh?" "hooray"
# [4,] "FALSE" "de" "huh?" "huh?"
# [5,] " TRUE" "f" "huh?" "hooray"
# [6,] " TRUE" "g" "huh?" "hooray"
当发生这种情况时,您的不同数据类型会丢失,而您的数据框样式索引不再起作用:
m['a']
# [1] NA
解决方案?使用简单的for循环:
wtf$huh1 = NA
for (i in 1:nrow(wtf)) {
wtf$huh1[i] = if(wtf[i, 'a']) "hooray" else "huh?"
}
如果你有一个函数foo
那么
wtf$huh2 = NA
for (i in 1:nrow(wtf)) {
wtf$huh1[i] = foo(wtf[i, 'a'])
}
没有矢量化的函数可以进行矢量化以避免需要循环:
foov = Vectorize(foo)
# then you can
wtf$huh4 = foov(wtf$a)
答案 1 :(得分:1)
解决此问题的最简单方法可能是使用ifelse
进行矢量化,因此您不需要处理循环,或apply
:
myfunc <- function(row) {
ifelse (row['a'] == T,'hooray','huh?')
}
wtf$huh <- myfunc(wtf)
a b a
1 TRUE a hooray
2 FALSE b huh?
3 TRUE c hooray
4 FALSE de huh?
5 TRUE f hooray
6 TRUE g hooray
答案 2 :(得分:1)
data.frame
的一个优点是它们可以包含不同类型变量的变量。
lapply(wtf, typeof)
$a
[1] "logical"
$b
[1] "factor"
$huh
[1] "character"
正如Gregor所说,apply
需要一个矩阵,如果可能的话,会将你给它的对象转换成一个。但是矩阵不能包含多个变量类型,因此as.matrix
将寻找可以表示数据的最小公分母,在本例中为字符。
typeof(as.matrix(wtf))
[1] "character"
class(as.matrix(wtf))
[1] "matrix"