首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >tidyr::收集缺少数据的na.rm

tidyr::收集缺少数据的na.rm
EN

Stack Overflow用户
提问于 2017-05-25 21:06:06
回答 3查看 1.6K关注 0票数 3

假设我在一个数据框架中有多个列来衡量相同的概念,但方法不同(例如,有多种类型的智商测试,学生可以有任何一种,或者根本就没有)。我想将各种方法组合成一个列(tidyr的明显用例)。

如果数据是这样的:

代码语言:javascript
复制
mydata <- data.frame(ID = 55:64, 
                 age = c(12, 12, 14, 11, 20, 10, 13, 15, 18, 17),
                 Test1 = c(100, 90, 88, 115, NA, NA, NA, NA, NA, NA),
                 Test2 = c(NA, NA, NA, NA, 100, 120, NA, NA, NA, NA),
                 Test3 = c( NA, NA, NA, NA, NA, NA, 110, NA, 85, 150))

我很自然地希望执行这样的操作(请注意,我使用na.rm = TRUE来避免数据集中的许多NA得到它们自己的行):

代码语言:javascript
复制
library(tidyr)
tests <- gather(mydata, key=IQSource, value=IQValue, c(Test1, Test2, Test3), na.rm = TRUE)
tests

给我:

ID age IQSource IQValue 1 55 12 Test1 100 2 56 12 Test1 90 3 57 14 Test1 88 4 58 11 Test1 115 15 59 20 Test2 100 16 60 10 Test2 120 27 61 13 Test3 110 29 63 18 Test3 85 30 64 17 Test3 150

问题是我有一个学生(ID=62)在这三个中没有任何一个智商分数,我不想失去她的其他数据( ID和年龄列中的数据)。

在tidyr中,是否有一种方法可以区分:是的,我想移除至少在我收集的一个列中有数据的NA,但同时希望在所有要收集的列都是NA的情况下防止数据丢失?)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-05-25 23:09:06

如果每个学生只能进行一次智商测试..。

代码语言:javascript
复制
library(tidyverse)

mydata %>%
  gather(key=IQSource, value=IQValue, Test1:Test3) %>%
  group_by(ID) %>%
  arrange(IQValue) %>%
  slice(1)

ID age IQSource IQValue 1 55 12 Test1 100 2 56 12 Test1 90 3 57 14 Test1 88 4 58 11 Test1 115 5 59 20 Test2 100 6 60 10 Test2 120 7 61 13 Test3 110 8 62 15 Test1 NA 9 63 18 Test3 85 10 64 17 Test3 150

如果每个学生都能进行多次智商测试..。

代码语言:javascript
复制
mydata %>%
  # Add an ID with multiple IQ tests
  bind_rows(data.frame(ID=65, age=13, Test1=100, Test2=100, Test3=NA)) %>%
  gather(key=IQSource, value=IQValue, Test1:Test3) %>%
  group_by(ID) %>%
  filter(!is.na(IQValue) | all(is.na(IQValue))) %>%
  filter(all(!is.na(IQValue)) | !duplicated(IQValue)) %>%
  arrange(ID, IQSource)

ID age IQSource IQValue 1 55 12 Test1 100 2 56 12 Test1 90 3 57 14 Test1 88 4 58 11 Test1 115 5 59 20 Test2 100 6 60 10 Test2 120 7 61 13 Test3 110 8 62 15 Test1 NA 9 63 18 Test3 85 10 64 17 Test3 150 11 65 13 Test1 100 12 65 13 Test2 100

票数 1
EN

Stack Overflow用户

发布于 2017-05-25 21:26:57

我没有找到直接的解决方案,但是您可以right_join返回原始的data.frame,然后取消选择不需要的所有列。

代码语言:javascript
复制
library(tidyr)
library(dplyr)

mydata %>% 
  gather(key, val, Test1:Test3, na.rm = T) %>%
  right_join(mydata) %>% 
  select(-contains("Test"))
#> Joining, by = c("ID", "age")
#>    ID age   key val
#> 1  55  12 Test1 100
#> 2  56  12 Test1  90
#> 3  57  14 Test1  88
#> 4  58  11 Test1 115
#> 5  59  20 Test2 100
#> 6  60  10 Test2 120
#> 7  61  13 Test3 110
#> 8  62  15  <NA>  NA
#> 9  63  18 Test3  85
#> 10 64  17 Test3 150

另外,您当然可以首先创建一个data.frame,其中包含您想要保留的所有变量,然后加入它:

代码语言:javascript
复制
id_data <- select(mydata, ID, age)

mydata %>% 
  gather(key, val, Test1:Test3, na.rm = T) %>%
  right_join(id_data)
票数 3
EN

Stack Overflow用户

发布于 2017-05-25 21:26:36

我认为这对你有好处:

代码语言:javascript
复制
    # make another data frame which has just ID and whether or not they missed all 3 tests
    missing = mydata %>% 
      mutate(allNA = is.na(Test1) & is.na(Test2) & is.na(Test3)) %>%
      select(ID, allNA)

    # Gather and keep NAs  
    tests <- gather(mydata, key=IQSource, value=IQValue, c(Test1, Test2, Test3), na.rm = FALSE)

    # Keep the rows that have a IQValue or missed all tests
    tests = left_join(tests, missing) %>% 
      filter(!is.na(IQValue) | allNA)
    # Remove duplicated rows of individuals who missed all exams
    tests = tests[!is.na(tests$IQValue) | !duplicated(tests[["ID"]]), ]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44189826

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档