【问题标题】:dplyr: Need help returning column index of first non-NA value in every rowdplyr:需要帮助返回每行中第一个非 NA 值的列索引
【发布时间】:2019-05-14 19:40:51
【问题描述】:

我最近开始尝试在 tidyverse 中编写所有代码。这有时使我遇到困难。这是一个我无法在 tidyverse 中完成的简单任务:我需要数据框中的一列,它返回左侧第一个非 na 值的位置索引。有谁知道如何在 dplyr 中使用 mutate 实现这一点?

这是所需的输出。

data.frame(                           
"X1"=c(100,rep(NA,8)),
"X2"=c(NA,10,rep(NA,7)),
"X3"=c(NA,NA,1000,1000,rep(NA,5)),
"X4"=c(rep(NA,4),25,50,10,40,50),
"FirstNonNaPosition"=c(1,2,3,3,4,4,4,4,4)
)

【问题讨论】:

标签: r dplyr


【解决方案1】:

NA 元素替换为 0 后,max.col 是一个更简单有效的 base R 选项

max.col(replace(df2[1:4], is.na(df2[1:4]), 0), 'first')

甚至

df2$FirstNonNaPosition <- max.col(!is.na(df2[1:4]), "first")
df2$FirstNonNaPosition
#[1] 1 2 3 3 4 4 4 4 4

对于tidyverse,一个可能的选项是pmap

df2 %>% 
  mutate(FirstNonNaPosition = pmap_int(.[-5], ~ 
                          which.max(!is.na(c(...)))))

或者包裹max.col

df2 %>% 
   mutate(FirstNonNaPosition = max.col(!is.na(.[-5]), 'first'))

数据

df2 <- structure(list(X1 = c(100, NA, NA, NA, NA, NA, NA, NA, NA), X2 = c(NA, 
10, NA, NA, NA, NA, NA, NA, NA), X3 = c(NA, NA, 1000, 1000, NA, 
NA, NA, NA, NA), X4 = c(NA, NA, NA, NA, 25, 50, 10, 40, 50), 
    FirstNonNaPosition = c(1, 2, 3, 3, 4, 4, 4, 4, 4)), 
    class = "data.frame", row.names = c(NA, 
-9L))

【讨论】:

  • 对。我可以从 dplyr 中完成这项工作,但我需要将其合并到管道中。我如何将其合并到 dplyr 命令中?
  • @mcmahon.an 我会使用pmap,即df2 %&gt;% mutate(FirstNonNaPosition = pmap(.[-5], ~ which.max(!is.na(c(..))))
  • @mcmahon.an 您可以在“管道”之外执行任何操作来生成向量,也可以将其放入mutate。这里可以直接复制代码做df2 %&gt;% mutate(newcol = max.col(!is.na(df2[1:4]), "first"))。 (可选)将df2 替换为.
【解决方案2】:

还有base R 的可能性:

apply(df, 1, which.max)

[1] 1 2 3 3 4 4 4 4 4

dplyr:

df %>%
 mutate(FirstNonNaPosition = apply(., 1, which.max))

对@Andrew 提到的场景的修改:

apply(df, 1, function(x) which.max(!is.na(x)))

dplyr:

df %>%
 mutate(FirstNonNaPosition = apply(., 1, function(x) which.max(!is.na(x))))

【讨论】:

  • 如果连续有多个非 NA 值,which.max 可能会失败。例如,如果第 5 行,X3 列是 10。
  • 对。所以我只需要让它抓住第一个。
  • @Andrew 我考虑了示例中的结构,但是,我包括了您提到的场景的可能性。谢谢你注意到它:)
【解决方案3】:

你也可以使用apply

data.frame(                           
"X1"=c(100,rep(NA,8)),
"X2"=c(NA,10,rep(NA,7)),
"X3"=c(NA,NA,1000,1000,rep(NA,5)),
"X4"=c(rep(NA,4),25,50,10,40,50),
"FirstNonNaPosition"=c(1,2,3,3,4,4,4,4,4)
) %>%
  mutate(First_Non_NA_Pos = apply(., 1, function(x) which(!is.na(x))[1]))

   X1 X2   X3 X4 FirstNonNaPosition First_Non_NA_Pos
1 100 NA   NA NA                  1                1
2  NA 10   NA NA                  2                2
3  NA NA 1000 NA                  3                3
4  NA NA 1000 NA                  3                3
5  NA NA   NA 25                  4                4
6  NA NA   NA 50                  4                4
7  NA NA   NA 10                  4                4
8  NA NA   NA 40                  4                4
9  NA NA   NA 50                  4                4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-24
    • 2017-12-15
    相关资源
    最近更新 更多