我在R里有张桌子,看起来是这样的:
ID Year Source_1999 Source_2000 Source_2001 Source_2002
1 1999 ABC ABC ABC ABC
2 2001 ABC BBB XYZ NA
3 2000 NA ABC BBB BBB
4 2001 NA NA NA NA
该表有许多行,还有相当多的"Source_“列--可能大约有50列。
我需要创建一个新列,说明是否有任何源列包含NA,但我只想检查“年份”列中大于或等于年份的年份。所以我的新桌子是这样的:
ID Year Source_1999 Source_2000 Source_2001 Source_2002 NA_check
1 1999 ABC ABC ABC ABC No
2 2001 ABC BBB XYZ NA Yes
3 2000 NA ABC BBB BBB No
4 2001 NA NA NA NA Yes
(新的"NA“列中的值可以是任何类型的二进制指示符)
我每年都尝试使用if循环和函数is.na(df,start_year:finish_year),但这似乎不起作用,而且效率也不高。
将来,我可能希望以这种方式检查其他列,即计数特定的值,或者对行进行求和,但是使用由今年列指定的起始列,因此我希望我可以调整任何答案来实现这一点。
任何帮助都很感激。谢谢
发布于 2018-09-04 01:01:37
这对gather
和tidyr
的spread
以及group_by
、dplyr
的mutate
和readr
的parse_number
来说都是一项不错的任务:
library(tidyverse)
mydata %>%
gather(source, value, starts_with("Source")) %>%
mutate(source_year = parse_number(source)) %>%
group_by(ID, Year) %>%
mutate(any_na = anyNA(value[Year <= source_year])) %>%
select(-source_year) %>%
spread(source, value)
# A tibble: 4 x 7
# Groups: ID, Year [4]
# ID Year any_na Source_1999 Source_2000 Source_2001 Source_2002
# <int> <int> <lgl> <chr> <chr> <chr> <chr>
# 1 1 1999 FALSE ABC ABC ABC ABC
# 2 2 2001 TRUE ABC BBB XYZ NA
# 3 3 2000 FALSE NA ABC BBB BBB
# 4 4 2001 TRUE NA NA NA NA
一步
首先,将数据从宽格式转换为长格式,并提取源列的年份。
mydata <- mydata %>%
gather(source, value, starts_with("Source")) %>%
mutate(source_year = parse_number(source))
mydata
# A tibble: 16 x 5
# ID Year source value source_year
# <int> <int> <chr> <chr> <dbl>
# 1 1 1999 Source_1999 ABC 1999
# 2 2 2001 Source_1999 ABC 1999
# 3 3 2000 Source_1999 NA 1999
# 4 4 2001 Source_1999 NA 1999
# 5 1 1999 Source_2000 ABC 2000
# ...
然后按ID和年份分组,以便在这些组中应用以下计算。用大于或等于组年的source_Years筛选值,并检查是否存在NA
值。
mydata <- mydata %>%
group_by(ID, Year) %>%
mutate(any_na = anyNA(value[Year <= source_year]))
mydata
# A tibble: 16 x 6
# Groups: ID, Year [4]
# ID Year source value source_year any_na
# <int> <int> <chr> <chr> <dbl> <lgl>
# 1 1 1999 Source_1999 ABC 1999 FALSE
# 2 2 2001 Source_1999 ABC 1999 TRUE
# 3 3 2000 Source_1999 NA 1999 FALSE
# 4 4 2001 Source_1999 NA 1999 TRUE
# 5 1 1999 Source_2000 ABC 2000 FALSE
# ...
最后,删除不再需要的yource_year列,并将数据从长格式转换为宽格式:
mydata <- mydata %>%
select(-source_year) %>%
spread(source, value)
数据
mydata <- tibble(ID = 1:4,
Year = c(1999L, 2001L, 2000L, 2001L),
Source_1999 = c("ABC", "ABC", NA, NA),
Source_2000 = c("ABC", "BBB", "ABC", NA),
Source_2001 = c("ABC", "XYZ", "BBB", NA),
Source_2002 = c("ABC", NA, "BBB", NA))
发布于 2018-09-04 01:29:55
以下是两种data.table
方法:
不一定是最快的:
dt[, NA_check := Reduce(`|`, lapply(paste0("Source_", 1999:2002),
function(x) x >= paste0("Source_", Year) & is.na(get(x))))]
转换成长格式:
checkNA <- melt(dt, id.vars=c("ID", "Year"), variable.factor=FALSE)[,
anyNA(value[variable >= paste0("Source_", Year)]),
by=.(ID, Year)]
dt[checkNA , on=.(ID, Year), NA_check := V1]
数据:
library(data.table)
dt <- fread("ID Year Source_1999 Source_2000 Source_2001 Source_2002
1 1999 ABC ABC ABC ABC
2 2001 ABC BBB XYZ NA
3 2000 NA ABC BBB BBB
4 2001 NA NA NA NA")
发布于 2018-09-04 07:38:56
下面是一个带有base R
的apply
选项,循环遍历行,获取第一个非NA元素的索引,从该元素中子集行元素,检查anyNA
中的NA,并在此基础上创建'No/Yes‘值。
df1$any_NA <- apply(df1[-(1:2)], 1, function(x)
c("No", "Yes")[anyNA(x[pmax(which(!is.na(x))[1], 1,
na.rm = TRUE):length(x)]) + 1])
df1$any_NA
#[1] "No" "Yes" "No" "Yes"
数据
df1 <- structure(list(ID = 1:4, Year = c(1999L, 2001L, 2000L, 2001L),
Source_1999 = c("ABC", "ABC", NA, NA), Source_2000 = c("ABC",
"BBB", "ABC", NA), Source_2001 = c("ABC", "XYZ", "BBB", NA
), Source_2002 = c("ABC", NA, "BBB", NA)), class = "data.frame", row.names = c(NA,
-4L))
https://stackoverflow.com/questions/52162344
复制