首页 > 解决方案 > 如何从因子级别创建新的数据框列(& 排除变异错误)

问题描述

我在 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

将级别函数替换回去,但没有循环会返回变异错误(注意,我重新运行了测试数据以重新开始)

> df <- mutate(df, levels(df$y)[1] = NA)
Error: unexpected '=' in "df <- mutate(df, levels(df$y)[1] ="

我继续得到同样的错误是我尝试使用 .data=df 来指定数据集或将 as.character()、paste() 或 paste0() 包装在 levels 函数周围——我在网上找到了其他各种解决方案. 如果我使用 %>% 管道重构代码,R 也不是很挑剔。

我的关卡代码替换(以及潜在的新手错误)中的等号出乎意料怎么办?非常感谢任何帮助!

标签: rdataframetidyversedplyrlevels

解决方案


根据收到的评论为其他人发布解决方案,因此我可以将此问题标记为已解决。 请放弃投票给@arg0naut91 和@Gregor 以获得他们的解决方案和指导帮助。

测试数据

df <- data.frame(x=c(1:5), y=letters[1:5])

解决方案 1:基础 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

推荐阅读