簡體   English   中英

在 R 中按類別計算百分比

[英]calculating percentages by category them in R

這是我的數據示例:

 df <- read.table(header = TRUE, text = "book pen desk ipad 3 4 3 4 3 0 0 3 0 3 0 2 1 3 2 1 4 1 4 3 0 0 3 1 2 1 3 2 0 2 1 0 4 2 2 2 0 1 2 1 1 4 1 4 2 0 1 3 4 3 2 0 4 0 4 2" )

邏輯是我想要三個類別:低、中和高。

例如,考慮列 book,值 0 和 1= Low , 2= Medium , 3 和 4= High 接下來,我想計算每個類別的百分比。 如下所示,對於列簿中的 Low,百分比為 42.85。 我希望所有列都有這樣的輸出。 請考慮這只是一個示例。 謝謝你的幫助

 Class Low Midium High book 42.85 xx xx pen xx xx xx desk xx xx xx ipad xx xx xx

ret <- t(sapply(df, function(a) {
  lbls <- factor(c("Low", "Medium", "High"))
  ct <- cut(a, c(0, 2, 4, Inf), right = FALSE, labels = lbls)
  table(ct)
}))

t(apply(ret, 1, function(z) 100*z/sum(z)))
#           Low   Medium     High
# book 42.85714 28.57143 28.57143
# pen  50.00000 35.71429 14.28571
# desk 35.71429 50.00000 14.28571
# ipad 35.71429 50.00000 14.28571

作為數據框:

out <- as.data.frame(t(apply(ret, 1, function(z) 100*z/sum(z))))
out$Class <- rownames(out)
# rownames(out) <- NULL # optional, if you don't want them
out <- out[,c(4,1:3)]
out
#      Class      Low   Medium     High
# book  book 42.85714 28.57143 28.57143
# pen    pen 50.00000 35.71429 14.28571
# desk  desk 35.71429 50.00000 14.28571
# ipad  ipad 35.71429 50.00000 14.28571

這是一個適合您的tidyverse解決方案:

library(tidyverse)

df <- read.table(header = TRUE, text =
                   "book  pen desk    ipad
3   4   3   4
3   0   0   3
0   3   0   2
1   3   2   1
4   1   4   3
0   0   3   1
2   1   3   2
0   2   1   0
4   2   2   2
0   1   2   1
1   4   1   4
2   0   1   3
4   3   2   0
4   0   4   2"
                 
)

df %>% 
  pivot_longer(1:4, 
               names_to = "Class", 
               values_to = "value") %>% 
  mutate(category = case_when(value %in% 0:1 ~ "l",
                              value == 2 ~ "m",
                              value %in% 3:4 ~ "h")) %>% 
  group_by(Class, category) %>% 
  count(category) %>% 
  pivot_wider(names_from = category, values_from = n) %>% 
  transmute(Class = Class,
            High = h / sum(h, m, l)*100,
            Medium = m / sum(h, m, l)*100,
            Low = l / sum(h, m, l)*100)

結果表:

# A tibble: 4 x 4
# Groups:   Class [4]
  Class  High Medium   Low
  <chr> <dbl>  <dbl> <dbl>
1 book   42.9   14.3  42.9
2 desk   35.7   28.6  35.7
3 ipad   35.7   28.6  35.7
4 pen    35.7   14.3  50  

附上一個可能的解決方案。 可能有更好的,但我會“自發地”想出它。

你好

df_test <- read.table(header = TRUE, text =
                   "book  pen desk    ipad
3   4   3   4
3   0   0   3
0   3   0   2
1   3   2   1
4   1   4   3
0   0   3   1
2   1   3   2
0   2   1   0
4   2   2   2
0   1   2   1
1   4   1   4
2   0   1   3
4   3   2   0
4   0   4   2"
                 
)

low <- list()
medium <- list()
high <- list()

for(i in 1:ncol(df_test)) # i=1
{
  low[[i]] <- ifelse((df_test[,i]==0 | df_test[,i]==1),df_test[,i],NA)
  low[[i]] <- sum(colSums(!is.na(t(low[[i]])))) / length(low[[i]]) *100
  medium[[i]] <- ifelse((df_test[,i]==2 | df_test[,i]==3),df_test[,i],NA)
  medium[[i]] <- sum(colSums(!is.na(t(medium[[i]])))) / length(medium[[i]]) *100
  high[[i]] <- ifelse((df_test[,i]==4 | df_test[,i]==5),df_test[,i],NA)
  high[[i]] <- sum(colSums(!is.na(t(high[[i]])))) / length(high[[i]]) *100
}

names(low) <- colnames(df_test)
names(medium) <- colnames(df_test)
names(high) <- colnames(df_test)

df_test_final <- data.frame("Class"=colnames(df_test),"Low"=NA,"Medium"=NA,"High"=NA)

df_test_final[,2] <- do.call(rbind,low)
df_test_final[,3] <- do.call(rbind,medium)
df_test_final[,4] <- do.call(rbind,high)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM