我想将百分比值作为data.frame
中的一列。示例代码有效。但问题是这是否是正确而优雅的R-way?
> df <- data.frame(addmargins(table(mtcars$gear, useNA="always")))
> df
Var1 Freq
1 3 15
2 4 12
3 5 5
4 <NA> 0
5 Sum 32
> df$percent <- mapply(function(x) {100 / length(mtcars$gear) * x}, df$Freq)
> df
Var1 Freq percent
1 3 15 46.875
2 4 12 37.500
3 5 5 15.625
4 <NA> 0 0.000
5 Sum 32 100.000
对我来说,没有必要将这个问题限制在data.frame
.
我认为添加边距是一种不好的做法,因为您将数据与摘要混合在一起。
df <- data.frame(table(mtcars$gear, useNA="always"))
df$pct <-df$Freq/sum(df$Freq)*100
df
#> Var1 Freq pct
#> 1 3 15 46.875
#> 2 4 12 37.500
#> 3 5 5 15.625
#> 4 <NA> 0 0.000
或者在惯用的dplyr
代码中(无需打扰table
(:
library(dplyr)
mtcars %>%
group_by(gear) %>%
summarise(Freq=n()) %>%
mutate(percent=Freq/sum(Freq)*100)
#> # A tibble: 3 x 3
#> gear Freq percent
#> <dbl> <int> <dbl>
#> 1 3 15 46.9
#> 2 4 12 37.5
#> 3 5 5 15.6
请注意,汇总后无需ungroup
,因为您只有一个分组变量,而汇总恰好剥离了一层分组
为了清楚起见,我提倡一个基于dplyr::mutate
的解决方案:
df <- df %>%
mutate(percent = (Freq/nrow(mtcars)) * 100)
我想我会在基本 R中使用table
函数来完成此任务(从一开始就使用它(:
df <- data.frame(
"g" = names(table(mtcars$gear)),
"f" = as.numeric(table(mtcars$gear)),
"p" = as.numeric(100 * (table(mtcars$gear)/length(mtcars$gear)))
)
结果如下:
> df
g f p
1 3 15 46.875
2 4 12 37.500
3 5 5 15.625
或者,在创建 data.frame 后添加百分比以获得较短的代码段:
df <- data.frame(table(mtcars$gear))
df$p <- 100 * (df[,'Freq'] / sum(df[,'Freq']))
给:
> df
Var1 Freq p
1 3 15 46.875
2 4 12 37.500
3 5 5 15.625
1( prop.tableprop.table
在这里很有用。 我们使用ave
将其分别应用于数据和摘要行。
transform(df, Percent = 100 * ave(Freq, Var1 == "Sum", FUN = prop.table))
给:
Var1 Freq Percent
1 3 15 46.875
2 4 12 37.500
3 5 5 15.625
4 <NA> 0 0.000
5 Sum 32 100.000
2(表格包 如果这样做的目的是显示指示的表格,那么表格包很好。 公式的 LHS 上的项是指行,RHS 上的项是指列。
library(tables)
gear <- factor(mtcars$gear)
tab <- tabular(gear + 1 ~ (n=1) + Percent())
给:
> tab
gear n Percent
3 15 46.88
4 12 37.50
5 5 15.62
All 32 100.00
HTML和LaTeX输出现在可以使用html(tab)
和latex(tab)
生成。
这种方法更适合显示,但如果你真的想提取数据,可以这样做:
m <- as.matrix(tab, format = as.numeric)
dimnames(m) <- list(attr(tab, "rowLabels"), attr(tab, "colLabels"))