Plyr 将 class 从数字更改为字符
Plyr changing class from numeric to character
当我尝试使用 ddply
来总结 data.frame 的某些方面时,如果我只包含产生数字数据的表达式,一切都很好。但是,如果我包含同时产生数字和字符数据的表达式,则所有输出列都会变成字符,这是我绝对没有预料到的,并且真的搞砸了我的下游代码。这是我正在谈论的可重现示例:
library(plyr)
set.seed(1234)
data <- data.frame(x = 1:25,
y = c((1:25)*4 + rnorm(100, mean = 0, sd = 50),
(1:25)*4 + rnorm(100, mean = 0, sd = 1000)),
category = c(rep("stuff with a stronger correlation", 100),
rep("stuff with a weaker correlation", 100)))
lmresults <- ddply(data, "category", function(df) c(
slope = coef(lm(df$y ~ df$x))[2],
pval = signif(summary(lm(df$y ~ df$x))$coef[2, "Pr(>|t|)"], 2)
))
str(lmresults)
此输出:
'data.frame': 2 obs. of 3 variables:
$ category : Factor w/ 2 levels "stuff with a stronger correlation",..: 1 2
$ slope.df$x: num 4.15 12.31
$ pval : num 3.7e-09 3.7e-01
注意 "slope" 和 "pval" 都是数字。但是,如果我这样做:
lmresults2 <- ddply(data, "category", function(df) c(
pval = signif(summary(lm(df$y ~ df$x))$coef[2, "Pr(>|t|)"], 2),
slope = paste("slope =", signif(coef(lm(df$y ~ df$x))[2], 2))
))
str(lmresults2)
输出为:
'data.frame': 2 obs. of 3 variables:
$ category: Factor w/ 2 levels "stuff with a stronger correlation",..: 1 2
$ pval : chr "3.7e-09" "0.37"
$ slope : chr "slope = 4.1" "slope = 12"
本来以为slope
是性格,没想到pval
也是性格!
这是 plyr 中的错误吗?是否将输出转换为矩阵,所有数据都必须具有相同的 class?但是如果是这样的话,为什么对象lmresults2
的class还是"data.frame"呢?
不,这不是错误。这是因为您在匿名函数中使用了 c()
。根据help(c)
:
All arguments are coerced to a common type which is the type of the returned value,
...
The output type is determined from the highest type of the components in the hierarchy NULL < raw < logical < integer < double < complex < character < list < expression.
您的第一个匿名函数连接了两个都产生数字的调用,因此没有问题。但是你的第二个匿名函数连接了一个用 signif()
创建的数字和一个由 paste()
创建的字符,因此给出了一个字符结果。
也许您想要 data.frame(pval = ..., slope = ...)
而不是 c()
。为了更简单地了解正在发生的事情,请查看 c(1, "a")
的结果。是数字还是字符?
当我尝试使用 ddply
来总结 data.frame 的某些方面时,如果我只包含产生数字数据的表达式,一切都很好。但是,如果我包含同时产生数字和字符数据的表达式,则所有输出列都会变成字符,这是我绝对没有预料到的,并且真的搞砸了我的下游代码。这是我正在谈论的可重现示例:
library(plyr)
set.seed(1234)
data <- data.frame(x = 1:25,
y = c((1:25)*4 + rnorm(100, mean = 0, sd = 50),
(1:25)*4 + rnorm(100, mean = 0, sd = 1000)),
category = c(rep("stuff with a stronger correlation", 100),
rep("stuff with a weaker correlation", 100)))
lmresults <- ddply(data, "category", function(df) c(
slope = coef(lm(df$y ~ df$x))[2],
pval = signif(summary(lm(df$y ~ df$x))$coef[2, "Pr(>|t|)"], 2)
))
str(lmresults)
此输出:
'data.frame': 2 obs. of 3 variables:
$ category : Factor w/ 2 levels "stuff with a stronger correlation",..: 1 2
$ slope.df$x: num 4.15 12.31
$ pval : num 3.7e-09 3.7e-01
注意 "slope" 和 "pval" 都是数字。但是,如果我这样做:
lmresults2 <- ddply(data, "category", function(df) c(
pval = signif(summary(lm(df$y ~ df$x))$coef[2, "Pr(>|t|)"], 2),
slope = paste("slope =", signif(coef(lm(df$y ~ df$x))[2], 2))
))
str(lmresults2)
输出为:
'data.frame': 2 obs. of 3 variables:
$ category: Factor w/ 2 levels "stuff with a stronger correlation",..: 1 2
$ pval : chr "3.7e-09" "0.37"
$ slope : chr "slope = 4.1" "slope = 12"
本来以为slope
是性格,没想到pval
也是性格!
这是 plyr 中的错误吗?是否将输出转换为矩阵,所有数据都必须具有相同的 class?但是如果是这样的话,为什么对象lmresults2
的class还是"data.frame"呢?
不,这不是错误。这是因为您在匿名函数中使用了 c()
。根据help(c)
:
All arguments are coerced to a common type which is the type of the returned value,
...
The output type is determined from the highest type of the components in the hierarchy NULL < raw < logical < integer < double < complex < character < list < expression.
您的第一个匿名函数连接了两个都产生数字的调用,因此没有问题。但是你的第二个匿名函数连接了一个用 signif()
创建的数字和一个由 paste()
创建的字符,因此给出了一个字符结果。
也许您想要 data.frame(pval = ..., slope = ...)
而不是 c()
。为了更简单地了解正在发生的事情,请查看 c(1, "a")
的结果。是数字还是字符?