如何从因子级别创建新的数据框列(并解决变异错误)
How to make new dataframe columns from factor levels (& troubleshoot mutate error)
我在 SO 和其他地方的搜索提出了有趣的解决方案,以解决具有相似搜索词但不是我的问题的问题。以为我找到了解决办法,但这个错误让我很困惑。我正在尝试更好地学习 tidyverse 方法,但我很欣赏任何解决方案策略。
目标: 在数据框中创建新的向量列,其中每个新向量都是根据现有数据框向量的因子级别命名的。
代码解决方案应该是动态的,以便它可以应用于具有任意数量级别的因素。
测试数据
df <- data.frame(x=c(1:5), y=letters[1:5])
按预期生成
> str(df)
'data.frame': 5 obs. of 2 variables:
$ x: int 1 2 3 4 5
$ y: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
> df
x y
1 1 a
2 2 b
3 3 c
4 4 d
5 5 e
完成后应该看起来像
> df
x y a b c d e
1 1 a NA NA NA NA NA
2 2 b NA NA NA NA NA
3 3 c NA NA NA NA NA
4 4 d NA NA NA NA NA
5 5 e NA NA NA NA NA
整洁的循环方法
library(tidyverse)
for (i in 1:length(levels(df$y))) {
df <- mutate(df, levels(df$y)[i] = NA)
}
但这给了我以下错误:
> for (i in 1:length(levels(df$y))) {
+ df <- mutate(df, levels(df$y)[i] = NA)
Error: unexpected '=' in:
"for (i in 1:length(levels(df$y))) {
df <- mutate(df, levels(df$y)[i] ="
> }
Error: unexpected '}' in "}"
故障排除,我删除了循环并简化了 mutate 以查看它是否总体上有效,它会带或不带引号 (注意,我重新运行测试数据以重新开始).
levels(df$y)[1]
> "a"
df <- mutate(df, a = NA)
df <- mutate(df, "a" = NA) # works the same as the previous line
> df
x y a
1 1 a NA
2 2 b NA
3 3 c NA
4 4 d NA
5 5 e NA
将级别函数替换回来,但没有循环 returns 变异错误 (注意,我重新运行测试数据以重新开始):
> df <- mutate(df, levels(df$y)[1] = NA)
Error: unexpected '=' in "df <- mutate(df, levels(df$y)[1] ="
我继续遇到同样的错误,因为我尝试使用 .data=df 指定数据集或将 as.character()、paste() 或 paste0() 包裹在水平函数周围——我在网上找到了其他各种解决方案。如果我使用 %>% 管道重构代码,R 也不只是挑剔。
对于我的关卡代码替换(以及潜在的新手错误),等号出乎意料怎么办?
非常感谢任何帮助!
根据收到的评论为其他人发布解决方案,这样我就可以将这个问题标记为已解决。 请投票给@arg0naut91 和@Gregor 以获得他们的解决方案和指导帮助。
测试数据
df <- data.frame(x=c(1:5), y=letters[1:5])
方案一:基础R
@arg0naut91 提供了一个优雅的基础 R 解决方案:
df[, levels(df$y)] <- NA
df
x y a b c d e
1 1 a NA NA NA NA NA
2 2 b NA NA NA NA NA
3 3 c NA NA NA NA NA
4 4 d NA NA NA NA NA
5 5 e NA NA NA NA NA
解决方案 2:使用 quo() 和 :=
@Gregor 的指导和有用的链接展示了一些函数,以及几乎所有的 tidyverse,并不像我们预期的那样计算对象。
第一次使用单个新列进行测试:
df <- data.frame(x=c(1:5), y=letters[1:5]) # refresh test data
varlevel <- levels(df$y)[1] # where level 1=a
df <- mutate(df, !!varlevel := NA)
rm(varlevel) # cleanup
df
x y a
1 1 a NA
2 2 b NA
3 3 c NA
4 4 d NA
5 5 e NA
然后将其放入for循环中,将每个因子水平捕获为一个新列:
df <- data.frame(x=c(1:5), y=letters[1:5]) # refresh test data
for (i in 1:length(levels(df$y))) {
+ varlevel <- levels(df$y)[i]
+ df <- mutate(df, !!varlevel := NA)
+ rm(varlevel) # cleanup
+ }
df
x y a b c d e
1 1 a NA NA NA NA NA
2 2 b NA NA NA NA NA
3 3 c NA NA NA NA NA
4 4 d NA NA NA NA NA
5 5 e NA NA NA NA NA
我在 SO 和其他地方的搜索提出了有趣的解决方案,以解决具有相似搜索词但不是我的问题的问题。以为我找到了解决办法,但这个错误让我很困惑。我正在尝试更好地学习 tidyverse 方法,但我很欣赏任何解决方案策略。
目标: 在数据框中创建新的向量列,其中每个新向量都是根据现有数据框向量的因子级别命名的。 代码解决方案应该是动态的,以便它可以应用于具有任意数量级别的因素。
测试数据
df <- data.frame(x=c(1:5), y=letters[1:5])
按预期生成
> str(df)
'data.frame': 5 obs. of 2 variables:
$ x: int 1 2 3 4 5
$ y: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
> df
x y
1 1 a
2 2 b
3 3 c
4 4 d
5 5 e
完成后应该看起来像
> df
x y a b c d e
1 1 a NA NA NA NA NA
2 2 b NA NA NA NA NA
3 3 c NA NA NA NA NA
4 4 d NA NA NA NA NA
5 5 e NA NA NA NA NA
整洁的循环方法
library(tidyverse)
for (i in 1:length(levels(df$y))) {
df <- mutate(df, levels(df$y)[i] = NA)
}
但这给了我以下错误:
> for (i in 1:length(levels(df$y))) {
+ df <- mutate(df, levels(df$y)[i] = NA)
Error: unexpected '=' in:
"for (i in 1:length(levels(df$y))) {
df <- mutate(df, levels(df$y)[i] ="
> }
Error: unexpected '}' in "}"
故障排除,我删除了循环并简化了 mutate 以查看它是否总体上有效,它会带或不带引号 (注意,我重新运行测试数据以重新开始).
levels(df$y)[1]
> "a"
df <- mutate(df, a = NA)
df <- mutate(df, "a" = NA) # works the same as the previous line
> df
x y a
1 1 a NA
2 2 b NA
3 3 c NA
4 4 d NA
5 5 e NA
将级别函数替换回来,但没有循环 returns 变异错误 (注意,我重新运行测试数据以重新开始):
> df <- mutate(df, levels(df$y)[1] = NA)
Error: unexpected '=' in "df <- mutate(df, levels(df$y)[1] ="
我继续遇到同样的错误,因为我尝试使用 .data=df 指定数据集或将 as.character()、paste() 或 paste0() 包裹在水平函数周围——我在网上找到了其他各种解决方案。如果我使用 %>% 管道重构代码,R 也不只是挑剔。
对于我的关卡代码替换(以及潜在的新手错误),等号出乎意料怎么办? 非常感谢任何帮助!
根据收到的评论为其他人发布解决方案,这样我就可以将这个问题标记为已解决。 请投票给@arg0naut91 和@Gregor 以获得他们的解决方案和指导帮助。
测试数据
df <- data.frame(x=c(1:5), y=letters[1:5])
方案一:基础R
@arg0naut91 提供了一个优雅的基础 R 解决方案:
df[, levels(df$y)] <- NA
df
x y a b c d e
1 1 a NA NA NA NA NA
2 2 b NA NA NA NA NA
3 3 c NA NA NA NA NA
4 4 d NA NA NA NA NA
5 5 e NA NA NA NA NA
解决方案 2:使用 quo() 和 :=
@Gregor 的指导和有用的链接展示了一些函数,以及几乎所有的 tidyverse,并不像我们预期的那样计算对象。
第一次使用单个新列进行测试:
df <- data.frame(x=c(1:5), y=letters[1:5]) # refresh test data
varlevel <- levels(df$y)[1] # where level 1=a
df <- mutate(df, !!varlevel := NA)
rm(varlevel) # cleanup
df
x y a
1 1 a NA
2 2 b NA
3 3 c NA
4 4 d NA
5 5 e NA
然后将其放入for循环中,将每个因子水平捕获为一个新列:
df <- data.frame(x=c(1:5), y=letters[1:5]) # refresh test data
for (i in 1:length(levels(df$y))) {
+ varlevel <- levels(df$y)[i]
+ df <- mutate(df, !!varlevel := NA)
+ rm(varlevel) # cleanup
+ }
df
x y a b c d e
1 1 a NA NA NA NA NA
2 2 b NA NA NA NA NA
3 3 c NA NA NA NA NA
4 4 d NA NA NA NA NA
5 5 e NA NA NA NA NA