使用 lapply() 查找因子变量的百分比
Use lapply() to find percentages of factor variables
我有一个数据框,包含 4 列代表问题,每列有 4 个水平代表回答。
Q1 Q2
1 A A
2 A B
3 B B
4 C C
5 D D
我想推导出一个 data.frame
这样的:
question response percent
1 Q2 A 0.2
2 Q2 B 0.4
3 Q2 C 0.2
4 Q2 D 0.2
5 Q1 A 0.4
6 Q1 B 0.2
7 Q1 C 0.2
8 Q1 D 0.2
到目前为止,我一直在使用 for
循环来实现这一点,但是我的脚本充满了 for
循环,所以我想使用 [=20= 中的函数来实现这一点] 或 lapply
。例如,这段代码比 for
循环要干净得多,但仍然不是我想要的。任何帮助将不胜感激!
这是我目前得到的:
lapply(lapply(df, summary), function(x) x/sum(x))
编辑: 包括每个请求的数据帧示例。本来怕占太多space因为关卡标签太长了,所以就缩短了。
dput(df[1:4,])
structure(list(Q1 = structure(c(4L, 4L, 1L, 4L), .Label = c("1.A",
"1.B", "1.C", "1.D"), class = "factor"),
Q2 = structure(c(4L, 4L, 4L, 1L), .Label = c("2.A","2.B",
"2.C", "2.D"), class = "factor"),
Q3 = structure(c(4L, 3L, 4L, 4L), .Label = c("3.A","3.B",
"3.C","3.D"), class = "factor"),
Q4 = structure(c(3L, 1L, 3L, 3L), .Label = c("4.A","4.B",
"4.C","4.D")),
.Names = c("Q1.pre", "Q2.pre", "Q3.pre", "Q4.pre"), row.names = c(NA, 4L),
class = "data.frame")
我发现 Lafortune 和 user20650 的回复几乎完全符合我一直在寻找的内容:
melt(sapply(df, function(x) prop.table(table(x))))
但是有一个问题。在 sapply
级别,dimnames
与 Q1 级别的标签名称相同,因此在执行 melt
之后 sapply
的输出,Var1 列是只是 Q1s 水平的重复,而我希望 Var1 在 Q1 行中有 Q1 的水平,在 Q2 行中有 Q2 的水平,等等。我找到了一个解决方法,将所有列的 levels
拉到一个单独的变量 qnames
before 对 df
执行任何操作,如下所示:
qnames = melt(sapply(df, levels))
qnames = qnames[ ,3]
melt(sapply(df, function(x) prop.table(table(x))))
df = cbind(qnames, df)
这正是我需要的结果。我很想知道是否有一种方法可以在没有额外的 sapply
和 cbind
的情况下实现这一点,所以我会把这个问题留长一点。感谢您的帮助!
library(reshape2)
indx <- lapply(df, function(x) prop.table(table(x)))
out <- melt(do.call(rbind, indx))
out <- out[order(out$Var1, decreasing=TRUE),];rownames(out) <- NULL
# Var1 Var2 value
# 1 Q2 A 0.2
# 2 Q2 B 0.4
# 3 Q2 C 0.2
# 4 Q2 D 0.2
# 5 Q1 A 0.4
# 6 Q1 B 0.2
# 7 Q1 C 0.2
# 8 Q1 D 0.2
您可以使用 lapply
和 reshape2
,但是 prop.table
是一个不错的功能。当它包装 table
函数时,它将为您计算百分比。我们使用 lapply
为每一列创建一个比例 table,然后将它们与始终如一的 do.call(rbind, lst)
组合起来。最后一行是 'look'.
单行使用 data.table
:
library(data.table) # 1.9.5+
dt<-data.table(Q1=c("A","A","B","C","D"),
Q2=c("A","B","B","C","D"))
rbindlist(lapply(
names(dt),
function(x)dt[,.N/nrow(dt),by=x
][,.(question=x,response=get(x),percent=V1)]))
我有一个数据框,包含 4 列代表问题,每列有 4 个水平代表回答。
Q1 Q2
1 A A
2 A B
3 B B
4 C C
5 D D
我想推导出一个 data.frame
这样的:
question response percent
1 Q2 A 0.2
2 Q2 B 0.4
3 Q2 C 0.2
4 Q2 D 0.2
5 Q1 A 0.4
6 Q1 B 0.2
7 Q1 C 0.2
8 Q1 D 0.2
到目前为止,我一直在使用 for
循环来实现这一点,但是我的脚本充满了 for
循环,所以我想使用 [=20= 中的函数来实现这一点] 或 lapply
。例如,这段代码比 for
循环要干净得多,但仍然不是我想要的。任何帮助将不胜感激!
这是我目前得到的:
lapply(lapply(df, summary), function(x) x/sum(x))
编辑: 包括每个请求的数据帧示例。本来怕占太多space因为关卡标签太长了,所以就缩短了。
dput(df[1:4,])
structure(list(Q1 = structure(c(4L, 4L, 1L, 4L), .Label = c("1.A",
"1.B", "1.C", "1.D"), class = "factor"),
Q2 = structure(c(4L, 4L, 4L, 1L), .Label = c("2.A","2.B",
"2.C", "2.D"), class = "factor"),
Q3 = structure(c(4L, 3L, 4L, 4L), .Label = c("3.A","3.B",
"3.C","3.D"), class = "factor"),
Q4 = structure(c(3L, 1L, 3L, 3L), .Label = c("4.A","4.B",
"4.C","4.D")),
.Names = c("Q1.pre", "Q2.pre", "Q3.pre", "Q4.pre"), row.names = c(NA, 4L),
class = "data.frame")
我发现 Lafortune 和 user20650 的回复几乎完全符合我一直在寻找的内容:
melt(sapply(df, function(x) prop.table(table(x))))
但是有一个问题。在 sapply
级别,dimnames
与 Q1 级别的标签名称相同,因此在执行 melt
之后 sapply
的输出,Var1 列是只是 Q1s 水平的重复,而我希望 Var1 在 Q1 行中有 Q1 的水平,在 Q2 行中有 Q2 的水平,等等。我找到了一个解决方法,将所有列的 levels
拉到一个单独的变量 qnames
before 对 df
执行任何操作,如下所示:
qnames = melt(sapply(df, levels))
qnames = qnames[ ,3]
melt(sapply(df, function(x) prop.table(table(x))))
df = cbind(qnames, df)
这正是我需要的结果。我很想知道是否有一种方法可以在没有额外的 sapply
和 cbind
的情况下实现这一点,所以我会把这个问题留长一点。感谢您的帮助!
library(reshape2)
indx <- lapply(df, function(x) prop.table(table(x)))
out <- melt(do.call(rbind, indx))
out <- out[order(out$Var1, decreasing=TRUE),];rownames(out) <- NULL
# Var1 Var2 value
# 1 Q2 A 0.2
# 2 Q2 B 0.4
# 3 Q2 C 0.2
# 4 Q2 D 0.2
# 5 Q1 A 0.4
# 6 Q1 B 0.2
# 7 Q1 C 0.2
# 8 Q1 D 0.2
您可以使用 lapply
和 reshape2
,但是 prop.table
是一个不错的功能。当它包装 table
函数时,它将为您计算百分比。我们使用 lapply
为每一列创建一个比例 table,然后将它们与始终如一的 do.call(rbind, lst)
组合起来。最后一行是 'look'.
单行使用 data.table
:
library(data.table) # 1.9.5+
dt<-data.table(Q1=c("A","A","B","C","D"),
Q2=c("A","B","B","C","D"))
rbindlist(lapply(
names(dt),
function(x)dt[,.N/nrow(dt),by=x
][,.(question=x,response=get(x),percent=V1)]))