【问题标题】:Summarizing using dplyr with a for loop使用带有 for 循环的 dplyr 进行总结
【发布时间】:2020-02-28 19:53:32
【问题描述】:

我想通过 for 循环使用 dplyr 将我的每个独立变量(列)与我的目标变量进行汇总。这是我的主要数据框:

 contract_ID Asurion 变量_1 变量_2 变量_3
         1 年 a c f
         2 年
         3 N b c g
         4 N a d f
         5 岁 b c f
         6 年

分组后我得到

a1 <- a %>% 
  group_by(Asurion,BhvrBnk_Donates_to_Env_Causes) %>%       
  summarise(counT=n_distinct(CONTRACT_ID)) %>%                                        
  mutate(perc=paste0(round(counT/sum(counT)*100,2),"%"))

 Asurion Variable_1 CounT   perc
    Y         a        3     75%
    Y         b        1     25%
    N         a        1     50%
    N         b        1     50%

我想对我的数据框中的每个变量进行总结,我想使用 for 循环来完成。我如何达到我想要的结果

这是我尝试使用的,但它似乎不起作用。这是一个学校项目,我需要为此使用 for 循环。请帮我看看这里

categorical <- colnames(a)###where categroical is the names of all columns in a  
###I would like to have a for loop for every column in a and summarise in the following way. I would like to store each of the summarisations in a separate dataframe 

for (i in categorical) {
  a[[i]] <- a %>% 
     group_by(Asurion,get(i)) %>% 
    summarise(counT=n_distinct(CONTRACT_ID)) %>% 
    mutate(perc=paste0(round(counT/sum(counT)*100,2),"%"))
  }

【问题讨论】:

  • 根据您的 cmets,您能否还包括预​​期的输出?这似乎是一个 xy 问题,如果您指出最终输出,人们可能会有不同的方法

标签: r for-loop group-by dplyr summarize


【解决方案1】:

您可能并不真的需要for loop 来获得您想要的东西。

df<-data.frame(contract_ID = 1:6, 
               Asurion = c("Y", "Y", "N", "N", "Y", "Y"), 
               Variable_1 = c("a", "a", "b", "a", "b","a"), 
               Variable_2 = c("c", "d", "c", "d", "c", "d"), 
               Variable_3 = c("f", "g", "g", "f", "f", "f"))

pct <- function(x) {
  df %>% 
  group_by(Asurion, {{x}}) %>% 
  summarise(counT=n_distinct(contract_ID)) %>% 
  mutate(perc = paste0(round(counT/sum(counT)*100,2),"%"))
}

pct(Variable_1)
pct(Variable_2)
pct(Variable_3)

如果您确实有很多变量,您可以使用 for loopapply 之类的东西来迭代最后一位。 这是一种选择:

categorical<- df[3:5]
a <- list()
j = 1
for (i in categorical) {
  a[[j]] <- df %>% 
    group_by(Asurion, {{i}}) %>% 
    summarise(counT=n_distinct(contract_ID)) %>% 
    mutate(perc = paste0(round(counT/sum(counT)*100,2),"%"))
  j = j + 1
}
a
[[1]]
# A tibble: 4 x 4
# Groups:   Asurion [2]
  Asurion `<fct>` counT perc 
  <fct>   <fct>   <int> <chr>
1 N       a           1 50%  
2 N       b           1 50%  
3 Y       a           3 75%  
4 Y       b           1 25%  

[[2]]
# A tibble: 4 x 4
# Groups:   Asurion [2]
  Asurion `<fct>` counT perc 
  <fct>   <fct>   <int> <chr>
1 N       c           1 50%  
2 N       d           1 50%  
3 Y       c           2 50%  
4 Y       d           2 50%  

[[3]]
# A tibble: 4 x 4
# Groups:   Asurion [2]
  Asurion `<fct>` counT perc 
  <fct>   <fct>   <int> <chr>
1 N       f           1 50%  
2 N       g           1 50%  
3 Y       f           3 75%  
4 Y       g           1 25%  

编辑 添加变量名称作为新变量值以响应您的问题以识别group_by 变量。

categorical<- df[3:5]
vnames <- colnames(categorical)
a <- list()
j = 1
for (i in categorical) {
  a[[j]] <- df %>% 
    group_by(Asurion, {{i}}) %>% 
    summarise(counT=n_distinct(contract_ID)) %>% 
    mutate(perc = paste0(round(counT/sum(counT)*100,2),"%"))
    a[[j]]$vnames = vnames[j]
  j = j + 1
}
a

【讨论】:

  • 感谢您的回答。我是编写循环的新手,因此想了解这里是否可以使用 for。跟进您的问题,我在数据集中确实有大约 50 个变量。我尝试使用:categorical &lt;-colnames(a) categorical &lt;- categorical[3:42]for (i in categorical) { a[[i]]&lt;- pct([i]) } 但似乎不起作用。我在这里做错了什么?
  • 谢谢你,这正是我想要的。但这里的问题是,因为它们都存储在一个列表中,当我将它们组合到一个数据框中时,我无法区分哪个变量给了我什么结果。有没有办法解决这个问题?我正在尝试这个b &lt;- list() j = 1 for (i in categorical) { b[[j]] &lt;- a %&gt;% group_by(Asurion, {{i}}) %&gt;% summarise(counT=n_distinct(CONTRACT_ID)) %&gt;% mutate(perc = paste0(round(counT/sum(counT)*100,2),"%"),v=colnames(i)) j = j + 1 }
  • 我还没有一个快速的答案。我自己还在学习{{。我认为理想的方法是 {{ 传递真正的变量名而不是 "&lt;fct&gt;"
  • 我已经添加了我的解决方案。
【解决方案2】:

基础 R 解决方案:

 df2 <- data.frame(

  reshape(df,

          direction = "long",

          varying = names(df)[!(names(df) %in% c("contract_ID", "Asurion"))],

          v.names = "Val",

          timevar = "Variable",

          times = names(df)[!(names(df) %in% c("contract_ID", "Asurion"))]

  ),

  row.names = NULL,

  stringsAsFactors = F

)

# Count the unique contract ids within the specified group: 

df2$CounT <- as.numeric(ave(df2$contract_ID,

                            paste(df2$Asurion, df2$Variable, df2$Val, sep = "_"),

                            FUN = function(x){length(unique(x))}))

# Create the percentage of total counts: 

df2$perc <- paste0(round((df2$CounT/as.numeric(ave(df2$Variable, 

                                                   paste(df2$Variable, df2$Val, sep = "_"),

                                                   FUN = length))) * 100,2),"%")

# Allocate some memory for list of dataframes: 

df_list <- vector("list", length(unique(df2$Variable)))

# Store the summary dataframes in the list: 

df_list <- lapply(split(df2, df2$Variable),

                  function(x){x <- unique(x[,c(!(names(x) %in% c("id", "contract_ID")))])})

# Push the dataframes from the list into the global environment: 

list2env(df_list, .GlobalEnv)

Tidyverse 解决方案:

require(tidyverse)

# Allocate some memory for list of dataframes: 

df_list <- vector("list", length(unique(names(df)[grepl("Variable_", names(df))])))

# Tidyverse summary: 

df_list <- 

  df %>% 

  gather(Variable, Value, -contract_ID, -Asurion) %>% 

  group_by(Asurion, Variable, Value) %>% 

  mutate(CounT = length(unique(contract_ID))) %>%

  ungroup() %>% 

  group_by(Variable, Value) %>% 

  mutate(perc = paste0(round((CounT/n()) * 100, 2), "%")) %>% 

  ungroup() %>% 

  select(-contract_ID) %>% 

  distinct() %>% 

  split(., .$Variable)

# Push the dataframes from the list into the global environment: 

list2env(df_list, .GlobalEnv)

数据:

structure(list(contract_ID = 1:6, Asurion = c("Y", "Y", "N", 
"N", "Y", "Y"), Variable_1 = c("a", "a", "b", "a", "b", "a"), 
    Variable_2 = c("c", "d", "c", "d", "c", "d"), Variable_3 = c("f", 
    "g", "g", "f", "f", "f")), class = "data.frame", row.names = c(NA, 
-6L))

【讨论】:

  • @Cole 从拆分和不同的函数中删除了 id 向量,结果应该是正确的。顺便说一句,您的解决方案非常雄辩。
【解决方案3】:

这是一种 方法,可以根据您的问题生成结果列表:

library(tidyr)
library(dplyr)

DF%>%
  add_count(Asurion, name = 'all_n')%>%
  pivot_longer(cols = starts_with('Variable'))%>%
  group_by(Asurion, name, value)%>%
  summarize(CounT = n(), 
            perc = n() / first(all_n))%>%
  ungroup()%>%
  group_split(name, keep = F)

[[1]]
# A tibble: 4 x 4
  Asurion value CounT  perc
  <fct>   <fct> <int> <dbl>
1 N       a         1  0.5 
2 N       b         1  0.5 
3 Y       a         3  0.75
4 Y       b         1  0.25

[[2]]
# A tibble: 4 x 4
  Asurion value CounT  perc
  <fct>   <fct> <int> <dbl>
1 N       c         1   0.5
2 N       d         1   0.5
3 Y       c         2   0.5
4 Y       d         2   0.5

[[3]]
# A tibble: 4 x 4
  Asurion value CounT  perc
  <fct>   <fct> <int> <dbl>
1 N       f         1  0.5 
2 N       g         1  0.5 
3 Y       f         3  0.75
4 Y       g         1  0.25

还有一个更符合预期输出的基本解决方案:

## base
lapply(grep('Variable', names(DF), value = T), # get vars starting with "Variable"
       function(col_name){
         t = table(DF[, c('Asurion', col_name)]) 
         data.frame(prop.table(t, 1), CounT = c(t))
       }
)

[[1]]
  Asurion Variable_1 Freq CounT
1       N          a 0.50     1
2       Y          a 0.75     3
3       N          b 0.50     1
4       Y          b 0.25     1

[[2]]
  Asurion Variable_2 Freq CounT
1       N          c  0.5     1
2       Y          c  0.5     2
3       N          d  0.5     1
4       Y          d  0.5     2

[[3]]
  Asurion Variable_3 Freq CounT
1       N          f 0.50     1
2       Y          f 0.75     3
3       N          g 0.50     1
4       Y          g 0.25     1

@Zhiqiang Wang 提供的数据:

DF<-data.frame(contract_ID = 1:6, 
               Asurion = c("Y", "Y", "N", "N", "Y", "Y"), 
               Variable_1 = c("a", "a", "b", "a", "b","a"), 
               Variable_2 = c("c", "d", "c", "d", "c", "d"), 
               Variable_3 = c("f", "g", "g", "f", "f", "f"))

【讨论】:

    猜你喜欢
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多