如何从要在循环中使用的数据框中提取列的名称?
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))
这是另一个没有任何循环的解决方案,使用 tidyr
和 broom
。
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
我想在 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))
这是另一个没有任何循环的解决方案,使用 tidyr
和 broom
。
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