我的目标非常简单-从调查中获取数据集并分析分数,每个感兴趣的目标群体给出每个潜在答案的频率。我的代码可以运行,但是它非常笨拙,因此容易出错。我想摆脱这两种情况,但是尽管进行了彻底的研究,但似乎仍然无法做到。
数据看起来像这样(请注意,Var *列包含零,这是不重要的,可以是二进制答案(仅0和1),也可以是多个答案(例如0到4),我需要以备后用):
head(my_data)
ID Gender AgeGroup Var1 Var2 Var3 Var4
1 1 1 1 1 2 3
2 1 2 0 0 1 2
3 2 1 1 1 2 1
4 1 2 1 1 1 2
5 2 1 0 1 3 1
6 1 2 0 1 2 1
理想情况下,我的最终输出应如下所示:
TG1 TG2 TG3
Var11 60.49% 56.67% 64.17%
Var21 67.3% 56.67% 77.54%
Var31 40.87% 39.44% 42.25%
Var32 27.27% 55.56% 21.23%
Var33 31.86% 5.0% 36.52%
我当前的脚本:
我首先创建数据的子集,其中包含感兴趣的目标组和一个空的数据框,以便以后保存结果:
TG1 <- subset (my_data, my_data$Gender == 1)
TG2 <- subset (my_data, my_data$Gender == 2)
TG3 <- subset (my_data, my_data$Var3 == 1 | my_data$Var3 == 2)
Results <- data.frame (TG1=numeric(0), TG2=numeric(0), TG3=numeric(0))
现在出现了一个巨大的循环:
rownames <- c() #Vector to hold the results temporarily
ColCounter <- 4 #Variable containing the column of the variable currently being calculated
while (ColCounter <= ncol(my_data)) {
ColCat <- max(my_data[,ColCounter]) #what is the maximum value in the current column?
Cat <- 1
while (Cat <= ColCat) {
t1 <- paste(round(sum(TG1[,ColCounter] == Cat)/nrow(TG1)*100, digits=2), "%", sep="")
t2 <- paste(round(sum(TG2[,ColCounter] == Cat)/nrow(TG2)*100, digits=2), "%", sep="")
t3 <- paste(round(sum(TG3[,ColCounter] == Cat)/nrow(TG3)*100, digits=2), "%", sep="")
Results[nrow(Results)+1,] <- c(t1,t2,t3)
rownames <- c(rownames, paste (strtrim(names(my_data[ColCounter]), 30), Cat, sep=""))
Cat <- Cat + 1
}
ColCounter <- ColCounter + 1
}
row.names(Results) <- make.names (rownames, unique=TRUE)
我认为通过编写一个函数来进行计算(可能还有另一个函数来获取每一列的最大类别数)并使用一个apply
函数来循环浏览,应该可以更容易地实现这一点。包含目标组的各种数据帧(保存在列表中)。以非常原始的方式编写:
TargetGroups <- lapply(ls(pattern = "TG[1-9]"), get)
names(TargetGroups) <- c("TG1", "TG2", "TG3")
Calc_Perc <- function (...) {
...
}
Results <- lapply(TargetGroups, Calc_Perc)
但是,到目前为止,尽管在列表上和数据框上使用apply
都读了这里和其他地方的大量条目,但我的所有方法都失败了。有什么好的方法可以做到这一点吗?
答案 0 :(得分:0)
这是一种tidyverse
方法。您的数据如上所述:
my_data <- read.table(text = "ID Gender AgeGroup Var1 Var2 Var3 Var4
1 1 1 1 1 2 3
2 1 2 0 0 1 2
3 2 1 1 1 2 1
4 1 2 1 1 1 2
5 2 1 0 1 3 1
6 1 2 0 1 2 1", header = TRUE)
首先将上面的组放入列表以方便使用:
groups_list <- list(
TG1 = subset(my_data, my_data$Gender == 1),
TG2 = subset(my_data, my_data$Gender == 2),
TG3 = subset(my_data, my_data$Var3 == 1 | my_data$Var3 == 2)
)
现在使用lapply
来应用一个函数,该函数首先将每个子集数据帧转换为长格式,获取每个组中每个答案的比例,然后针对groups_list
中的每个数据帧输出这些比例(更多详细信息)在评论中):
list_proportion_dfs <- lapply(names(groups_list), function(x) {
## Convert to long format
long = groups_list[[x]] %>%
gather(key = var, value = val, -c(ID, Gender, AgeGroup))
proportions = long %>%
### Group by variable and value
group_by(var, val) %>%
### Assign the length of each grouping
### to the new variable 'n'
summarize(n = n()) %>%
### Convert to a proportion by dividing
### n by the sum of n for the current
### 'var' grouping
mutate(
var.combo = paste(var, val, sep = ""),
x = n / sum(n) * 100
) %>%
ungroup() %>%
### Keep only the important rows
select(var.combo, x)
names(proportions) <- c("var.combo", x)
return(proportions)
})
输出如下:
> list_proportion_dfs
[[1]]
# A tibble: 9 x 2
var.combo TG1
<chr> <dbl>
1 Var10 50
2 Var11 50
3 Var20 25
4 Var21 75
5 Var31 50
6 Var32 50
7 Var41 25
8 Var42 50
9 Var43 25
[[2]]
# A tibble: 6 x 2
var.combo TG2
<chr> <dbl>
1 Var10 50
2 Var11 50
...
...
现在,您可以使用Reduce
和merge
(根据this answer)接近所需的结果:
output <- Reduce(function(x, y) merge(x, y, all = TRUE), list_proportion_dfs)
将NA值转换为零:
output[is.na(output)] <- 0
您的(未格式化的)结果如下:
> output
var.combo TG1 TG2 TG3
1 Var10 50 50 40
2 Var11 50 50 60
3 Var20 25 0 20
4 Var21 75 100 80
5 Var31 50 0 40
6 Var32 50 50 60
7 Var33 0 50 0
8 Var41 25 100 40
9 Var42 50 0 40
10 Var43 25 0 20
我很确定数学是正确的,因为给定的组/变量组合的所有比例都加到100%(示例输出不是这种情况)。如果我误解了您实际要查找的百分比,则可能需要弄乱分组顺序/级别。
为使输出更接近您显示的内容(同时避免使用多个“%”符号,您可以这样做:
rownames(output) <- output$var.combo
output <- select(output, -var.combo)
names(output) <- c(paste(names(output), "(%)"))
> output
TG1 (%) TG2 (%) TG3 (%)
Var10 50 50 40
Var11 50 50 60
Var20 25 0 20
Var21 75 100 80
Var31 50 0 40
Var32 50 50 60
Var33 0 50 0
Var41 25 100 40
Var42 50 0 40
Var43 25 0 20
但是我想您可能还是用RMarkdown或Excel进行了格式化。