【问题标题】:Count how many values in some cells of a row are not NA (in R)计算一行的某些单元格中有多少值不是 NA(在 R 中)
【发布时间】:2016-09-22 20:14:07
【问题描述】:

我有一个包含很多列的数据框。对于数据框的每一行,我想计算有多少列是 NA。问题是我只对其中的几列感兴趣,并且想(有效地)调用这些列。

在下面的假样本中使用 mutate 的方式给了我正确的答案。

library(stringr)

df  <- data_frame(
         id = 1:10
       , name = fruit[1:10]
       , word1 = c(words[1:5],NA,words[7:10])
       , word2 = words[11:20]
       , word3 = c(NA,NA,NA,words[25],NA,NA,words[32],NA,NA,words[65])
    ) %>%
    mutate(
        n_words = 
            as.numeric(!is.na(word1)) + 
            as.numeric(!is.na(word2)) + 
            as.numeric(!is.na(word3)) 
    )

但是,即使对于像这样的玩具示例,打字和阅读也很痛苦——当我要计算超过 3 列时,它在很大程度上是无用的。有没有更多的 R/dplyr-y 方式来写这个,也许使用select() 样式语法(例如n_words = !count_blank(word1:word3))?

我考虑过使用summarize() sans 分组,但是,我需要我正在计算的列中的数据,如果我将它们添加到group_by,我将再次调用几乎所有列。

【问题讨论】:

  • 试试rowSums(is.na(df[startsWith(names(df), "word")])),但我很困惑。您声明“我想计算有多少列是 NA”,但调用该列 word_count。您想要计算 NA 还是非 NA?
  • rowSums(!is.na(df[startsWith(names(df), "word")])) 改为

标签: r dplyr


【解决方案1】:

您可以在选定的列上使用is.na(),然后rowSums() 结果:

library(stringr)
df <- data_frame(
  id = 1:10
  , name = fruit[1:10]
  , word1 = c(words[1:5],NA,words[7:10])
  , word2 = words[11:20]
  , word3 = c(NA,NA,NA,words[25],NA,NA,words[32],NA,NA,words[65]))

df$word_count <- rowSums( !is.na( df [,3:5]))

df
      id         name    word1     word2   word3 n_words
   <int>        <chr>    <chr>     <chr>   <chr>   <dbl>
1      1        apple        a    actual    <NA>       2
2      2      apricot     able       add    <NA>       2
3      3      avocado    about   address    <NA>       2
4      4       banana absolute     admit   agree       3
5      5  bell pepper   accept advertise    <NA>       2
6      6     bilberry     <NA>    affect    <NA>       1
7      7   blackberry  achieve    afford alright       3
8      8 blackcurrant   across     after    <NA>       2
9      9 blood orange      act afternoon    <NA>       2
10    10    blueberry   active     again   awful       3

编辑

使用dplyr 你可以这样做:

df %>% 
    select(3:5) %>% 
    is.na %>% 
    `!` %>% 
    rowSums

【讨论】:

  • 我喜欢这个解决方案不依赖于正则表达式的方式(这不是真正的问题——如果列名将被命名为一致的东西,那么所有的赌注都会被取消)。不过,有什么办法可以在 dplyr 链中获得它?
【解决方案2】:
library(dplyr)
library(stringr)

df  <- data_frame(
  id = 1:10
  , name = fruit[1:10]
  , word1 = c(words[1:5],NA,words[7:10])
  , word2 = words[11:20]
  , word3 = c(NA,NA,NA,words[25],NA,NA,words[32],NA,NA,words[65])
) 

library(purrr)
# Rowwise sum of NAs
df %>% by_row(~ sum(is.na(.)), .collate = 'cols')

# Rowwise sum of non-NAs for word columns
df %>% 
  select(starts_with('word')) %>% 
  by_row(~ sum(!is.na(.)), .collate = 'cols')

【讨论】:

  • 对于最近阅读此内容的任何人,purrr::by_row() 已被删除。
  • 但是如果你想执行类似的方法,dplyr 已经获得了rowwise
  • 虽然不推荐使用 purrr,但 by_row 函数现在位于 purrrlyr 包中,其中包含一些描述为“在 dplyr 和 purrr 的交叉点”的函数。
  • 我尝试将df %&gt;% rowwise() %&gt;% mutate(n_notNA = sum(!is.na(c_across()))) 与包含混合类型列的数据集一起使用,并收到错误消息“错误:'mutate()' 输入'n_notNA' 出现问题。x 无法组合'xxx ' 和 'yyy' 。"似乎 c_across() 无法处理混合类型的列。如何更正我的代码?
  • 试试这样的:... mutate(n_notNA = sum(!is.na(c_across(where(is.numeric)))) 或使用另一个tidyselect syntax
【解决方案3】:

另一个dplyr解决方案:

library(stringr)

## define count function

count_na <- function(x) sum(!is.na(x))

df$count_na <- df %>%

  select(starts_with("word")) %>%

    apply(., 1, count_na)

## A tibble: 10 × 6
      id         name    word1     word2   word3 n_words
   <int>        <chr>    <chr>     <chr>   <chr>   <int>
1      1        apple        a    actual    <NA>       2
2      2      apricot     able       add    <NA>       2
3      3      avocado    about   address    <NA>       2
4      4       banana absolute     admit   agree       3
5      5  bell pepper   accept advertise    <NA>       2
6      6     bilberry     <NA>    affect    <NA>       1
7      7   blackberry  achieve    afford alright       3
8      8 blackcurrant   across     after    <NA>       2
9      9 blood orange      act afternoon    <NA>       2
10    10    blueberry   active     again   awful       3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-15
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多