【问题标题】:Nested Dataframe loses format after mutating with ifelse-condition嵌套数据框在使用 ifelse 条件发生变异后丢失格式
【发布时间】:2020-11-07 01:37:29
【问题描述】:

我正在尝试使用 ifelse 条件更改嵌套数据框中的新变量。但问题是在实现 ifelse 条件后,嵌套的数据框变成了一个列表。 我想用iris 数据集展示这个问题:

这里可以看到原来的嵌套格式:

iris %>% nest(data = -Species)

# A tibble: 3 x 2
  Species    data             
  <fct>      <list>           
1 setosa     <tibble [50 x 4]>
2 versicolor <tibble [50 x 4]>
3 virginica  <tibble [50 x 4]>

现在我想在嵌套数据框中改变一个新变量:

iris %>%
  nest(data = -Species) %>%
  mutate(data = map(data, function(x)
    x %>% mutate(`Sepal.Length^2` = Sepal.Length^2)))

# A tibble: 3 x 2
  Species    data             
  <fct>      <list>           
1 setosa     <tibble [50 x 5]>
2 versicolor <tibble [50 x 5]>
3 virginica  <tibble [50 x 5]>

此代码有效。 data-column 在 tibble 格式中是所需的。

但如果我现在插入 ifelse 条件,则 tibble 格式会丢失:

iris %>%
  nest(data = -Species) %>%
  mutate(data = map(data, function(x)
    ifelse(!is.na(x), x %>% mutate(`Sepal.Length^2` = Sepal.Length^2), NA)))

# A tibble: 3 x 2
  Species    data        
  <fct>      <list>      
1 setosa     <list [200]>
2 versicolor <list [200]>
3 virginica  <list [200]>

即使使用ifelse-条件,我也想保留tibble-格式。

谁能帮帮我?

【问题讨论】:

  • 我认为您必须先创建新列,然后执行 ifelse 条件。所以像... map(... function(x) mutate(x, ifelse(...)))
  • 在我的原始数据集中这是不可能的,因为在NA-colum 中有一些NA-values。所以首先我必须使用 ifelse 函数“过滤”数据。
  • 但是只有在没有 NA 的情况下,您才不会发生变异。你正在变异,然后你处理这些条件。所以ifelse(!is.na(x), x^2, x)。但也许我在你的解释中遗漏了一些东西
  • 它适用于if-function 而不是ifelse-function

标签: r if-statement nested


【解决方案1】:

map()计算的第一步,即setosa中的数据,你自定义函数的输入x其实是

x <- iris[1:50, 1:4]

然后你把x 放入ifelse()

ifelse(!is.na(x),                                        # part 1
       x %>% mutate(`Sepal.Length^2` = Sepal.Length^2),  # part 2
       NA)                                               # part 3

第一部分是!is.na(x),它返回50x4=200逻辑值。因此,第二部分和第三部分将被回收到长度 200。但是,第二部分,即

x %>% mutate(`Sepal.Length^2` = Sepal.Length^2)

是一个有5个变量的tibble,也是一个长度为5的list,所以这个tibble中的每个变量都会被回收40次,随后会创建一个长度为200的list。这就是为什么你会得到 3 个长度为 200 的列表。


在您的情况下,ifelse() 可能不适用。您可以将其调整为

iris %>%
  nest(data = -Species) %>%
  add_row(Species = "example", data = NA) %>% 
  mutate(data = map(data, function(x) {
    if(is.data.frame(x))
      x %>% mutate(`Sepal.Length^2` = Sepal.Length^2)
    else
      NULL
  }))

# # A tibble: 4 x 2
#   Species    data             
#   <chr>      <list>           
# 1 setosa     <tibble [50 × 5]>
# 2 versicolor <tibble [50 × 5]>
# 3 virginica  <tibble [50 × 5]>
# 4 example    <NULL>   

确保if() 中的条件必须是单个逻辑值。


感谢 @27ϕ9 提供map_if() 的简洁版本:

iris %>%
  nest(data = -Species) %>%
  add_row(Species = "example", data = NA) %>% 
  mutate(data = map_if(data, is_tibble,
                       ~ mutate(.x, `Sepal.Length^2` = Sepal.Length^2),
                       .else = NULL))

【讨论】:

  • 感谢您的回答。但是我在原始数据集中的data-colum 中有NA-values。因此,您的代码在我的情况下不起作用。
  • 此示例数据集将是更好的基础:iris %&gt;% nest(data = -Species)%&gt;% add_row(Species="example",data=NA)
  • 在我的情况下,它现在可以与if-函数一起使用,但不能与ifelse-函数一起使用。我无法解释为什么。此外,我现在使用is_tibble(x)if(is_tibble(x)) x %&gt;% mutate("Sepal.Length^2" = Sepal.Length^2)
  • @TobKel is_tibble(x) 很棒。请注意,ifelse() 不等同于 if...else...。它们适用于不同的情况。您可以搜索?ifelse了解更多详情。
  • @27ϕ9 感谢您的回复。但我倾向于通过对 OP 代码的最小修改来回答这个问题,并关注ifelse()if...else 的区别。我会将您的建议添加到我的答案中。这是一个很好的观点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多