【问题标题】:How to make new dataframe columns from factor levels (& troubleshoot mutate error)如何从因子级别创建新的数据框列(& 排除变异错误)
【发布时间】:2020-02-10 19:48:18
【问题描述】:

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

整洁的 for 循环方法

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

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

> 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 也不是很挑剔。

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

【问题讨论】:

  • 我不知道为什么不只是像df[, levels(df$y)] &lt;- NA这样的东西?
  • 您传递给函数的参数名称不会被评估。也就是说,foo = "na.rm"; mean(c(1, NA), foo = TRUE)) 之类的东西不起作用。这或多或少是您尝试使用levels(df$y)[i] = NA 失败的原因。阅读Programming with dplyr 小插图以了解解决方法。或者,对于最新的方法,尝试使用来自rlang as shown in this answer{{:=
  • 谢谢@arg0naut91!您的解决方案简短、优雅且有效!方法如此简单,我完全无法理解。

标签: r dataframe tidyverse dplyr levels


【解决方案1】:

根据收到的 cmets 为其他人发布解决方案,因此我可以将此问题标记为已解决。 请放弃对@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

【讨论】:

    猜你喜欢
    • 2021-06-10
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多