如何从要在循环中使用的数据框中提取列的名称?

How to extract the name of a column from a data frame to be used in the loop?

我想在 for 循环中逐一复制数据框列名的文本。我的代码似乎 return 来自列名参数的 NULL 值。

更广泛地说,我想根据几列中的每一列创建一个摘要。

# Create an example data frame
df <- data.frame( c( "a", "b", "c", "b", "c"), c( 6, 4, 10, 9, 11), c( 1, 3, 5, 3, 6))

colnames(df) <- c( "Group", "Num.Hats", "Num.Balls")

现在我想遍历第二列和第三列,创建一个按组存储汇总统计数据的数据对象。重点是看看 A、B 和 C 组在球和帽子方面有何不同。

我的代码如下所示:

# Evaluate stats of each group
for (i in 2:3){
    assign(paste0("Eval.", colnames(df[[i]])), tapply(df[,i], df$Group, summary))
}

我得到一个名为 "Eval." 的对象,其中包含 Num.Balls 的汇总统计信息。明确地说,我想要两个对象,一个叫 Eval.Num.Hats,一个叫 Eval.Num.Balls

如果colnames()不能这样使用,请问还有其他功能可以达到我想要的效果吗?或者,如果不需要循环,我愿意接受另一种解决方案。

df[[i]] 正在将列提取为 vector,但没有 colnames。我们可以使用 df[i] 或者正确的选项是 colnames(df)[i]

for (i in 2:3){
    assign(paste0("Eval.", colnames(df)[i]), tapply(df[,i], df$Group, summary))
 }

-输出

Eval.Num.Hats
#$a
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#      6       6       6       6       6       6 

#$b
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   4.00    5.25    6.50    6.50    7.75    9.00 

#$c
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#  10.00   10.25   10.50   10.50   10.75   11.00 

Eval.Num.Balls
#$a
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#      1       1       1       1       1       1 

#$b
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#      3       3       3       3       3       3 

#$c
#   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#   5.00    5.25    5.50    5.50    5.75    6.00 

您可以完全避免 for 循环。

解释:

在这里,我使用 lapply 遍历所有要汇总的列(使用它们的名称),除了用于分组的第一个列(参见 names(df1)[-1] returns ).

with 函数基本上附加了数据框,所以你不需要做 dataframe$column,你可以简单地输入列名。

by(variable to function, grouping variable, function)用于分组申请summary

我们需要使用列名作为变量而不是字符。这就是为什么我使用 mget() 将列的字符名称转换为变量的原因。

smry.ls.df1 <- lapply(names(df1)[-1], function(col) with(df1, by(mget(col), Group, summary)))
names(smry.ls.df1) <- paste0("Eval.", names(df1)[-1]) #setting the names as you've shown
smry.list.df1

#> $Eval.Num.Hats
#> Group: a
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>       6       6       6       6       6       6 
#> -------------------------------------------------------- 
#> Group: b
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>    4.00    5.25    6.50    6.50    7.75    9.00 
#> -------------------------------------------------------- 
#> Group: c
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>   10.00   10.25   10.50   10.50   10.75   11.00 
#> 
#> $Eval.Num.Balls
#> Group: a
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>       1       1       1       1       1       1 
#> -------------------------------------------------------- 
#> Group: b
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>       3       3       3       3       3       3 
#> -------------------------------------------------------- 
#> Group: c
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#>    5.00    5.25    5.50    5.50    5.75    6.00

如果你想将它们保存为单独的对象(不推荐)你可以使用list2env:

list2env(smry.list.df1, globalenv())

数据:

df1 <- data.frame(Group = c( "a", "b", "c", "b", "c"), 
                  Num.Hats = c( 6, 4, 10, 9, 11), 
                  Num.Balls = c( 1, 3, 5, 3, 6))

这是另一个没有任何循环的解决方案,使用 tidyrbroom

library(tidyr)
library(broom)

df %>%
  #Change from wide to long format
  pivot_longer(cols = c("Num.Hats","Num.Balls"),
               names_to = "Var") %>%
  #group by Group (a,b,c) and Var (Num.Hats, Num.Balls)
  group_by(Group, Var) %>%
  #Calculate the summary function for each group
  do(tidy(summary(.$value)))

# A tibble: 6 x 8
# Groups:   Group, Var [6]
#  Group Var    minimum    q1 median  mean    q3 maximum
#  <fct> <chr>    <dbl> <dbl>  <dbl> <dbl> <dbl>   <dbl>
#1 a     Num.B~       1  1       1     1    1          1
#2 a     Num.H~       6  6       6     6    6          6
#3 b     Num.B~       3  3       3     3    3          3
#4 b     Num.H~       4  5.25    6.5   6.5  7.75       9
#5 c     Num.B~       5  5.25    5.5   5.5  5.75       6
#6 c     Num.H~      10 10.2    10.5  10.5 10.8       11