假设我在一个数据框架中有多个列来衡量相同的概念,但方法不同(例如,有多种类型的智商测试,学生可以有任何一种,或者根本就没有)。我想将各种方法组合成一个列(tidyr的明显用例)。
如果数据是这样的:
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得到它们自己的行):
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的情况下防止数据丢失?)
发布于 2017-05-25 23:09:06
如果每个学生只能进行一次智商测试..。
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
如果每个学生都能进行多次智商测试..。
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
发布于 2017-05-25 21:26:57
我没有找到直接的解决方案,但是您可以right_join返回原始的data.frame,然后取消选择不需要的所有列。
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,其中包含您想要保留的所有变量,然后加入它:
id_data <- select(mydata, ID, age)
mydata %>%
gather(key, val, Test1:Test3, na.rm = T) %>%
right_join(id_data)发布于 2017-05-25 21:26:36
我认为这对你有好处:
# 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"]]), ]https://stackoverflow.com/questions/44189826
复制相似问题