根据第一个和最后一个非缺失值的不同条件,我很难以不同的方式填写NA。
背景:人们接受白内障手术并将晶状体状态从phak
更改为pseudo
。如果第一个非缺失值是“ phak”,则该值必须存在于以前未记录的观测值中。如果最后一个非缺失值是'pseudo',则可以继续执行此操作,因为状态不能更改回'phak'。
一个人不能简单地使用zoo::na.locf
之类的函数,因为如果开关之间不存在NA,我们将无法分辨确切的时间是什么,这些值应该保持NA。 Thus, it is not a "sandwich" problem
library(tidyverse)
a <- c(NA, 'phak', NA, 'pseudo', NA)
b <- c(NA, 'pseudo', NA, NA, NA)
c <- c('phak', 'phak', NA, NA, NA)
dfoo <- data.frame(a,b,c, stringsAsFactors = FALSE) %>% gather(eye, status)
dfoo
#> eye status
#> 1 a <NA>
#> 2 a phak
#> 3 a <NA>
#> 4 a pseudo
#> 5 a <NA>
#> 6 b <NA>
#> 7 b pseudo
#> 8 b <NA>
#> 9 b <NA>
#> 10 b <NA>
#> 11 c phak
#> 12 c phak
#> 13 c <NA>
#> 14 c <NA>
#> 15 c <NA>
所需数据帧:
#> eye status
#> 1 a phak
#> 2 a phak
#> 3 a <NA>
#> 4 a pseudo
#> 5 a pseudo
#> 6 b <NA>
#> 7 b pseudo
#> 8 b pseudo
#> 9 b pseudo
#> 10 b pseudo
#> 11 c phak
#> 12 c phak
#> 13 c <NA>
#> 14 c <NA>
#> 15 c <NA>
以下内容适用于简单的向量,但我很难在一个数据帧中按组使用此解决方案。
# by vector:
# first conditionally replace leading NAs
if(a[min(which(!is.na(a)))] == 'phak') {a[1 : min(which(!is.na(a)))] <- 'phak'}
# next conditionally replace last NAs
if(a[max(which(!is.na(a)))] == 'pseudo') {a[max(which(!is.na(a))): length(a)] <- 'pseudo'}
a
#> [1] "phak" "phak" NA "pseudo" "pseudo"
由reprex package(v0.3.0)于2019-12-16创建
答案 0 :(得分:3)
这是一种可能的整理方法:
group_by
视线水平phak
和pseudo
,分别将所有"pseudo"
值和"phak"
值替换为NA
fill
使用phak
的{{1}}列.direction = "up"
使用fill
的{{1}}列pseudo
.direction = "down"
和coalesce
列一起回到列phak
pseudo
数据
status
答案 1 :(得分:2)
这是使用自定义函数的另一种方法
apply_fun <- function(x) {
inds1 <- which(x == 'phak')
if(length(inds1) > 0) x[1:min(inds1)] <- 'phak'
inds2 <- which(x == 'pseudo')
if(length(inds2) > 0) x[max(inds2):length(x)] <- 'pseudo'
return(x)
}
library(dplyr)
dfoo %>% group_by(eye) %>% mutate(status = apply_fun(status))
# eye status
# <chr> <chr>
# 1 a phak
# 2 a phak
# 3 a NA
# 4 a pseudo
# 5 a pseudo
# 6 b NA
# 7 b pseudo
# 8 b pseudo
# 9 b pseudo
#10 b pseudo
#11 c phak
#12 c phak
#13 c NA
#14 c NA
#15 c NA
答案 2 :(得分:2)
我找到了在group_by %>% mutate
中使用if else构造的解决方案。此后可以删除中间变量,或者重写case_when
以包括它们。
dfoo %>%
group_by(eye) %>%
mutate(
changePhak = if(any(status == "phak", na.rm = TRUE)) row_number() < which(status == "phak") else FALSE,
changePseudo = if(any(status == "pseudo", na.rm = TRUE)) row_number() > which(status == "pseudo") else FALSE,
status = case_when(
changePhak ~ "phak",
changePseudo ~ "pseudo",
TRUE ~ status
)
)
答案 3 :(得分:0)
我想出了一种方法,但这似乎不是最好的解决方案,尤其是当我有成千上万的群组时,这种解决方案会杀死我的计算机:
1)首先按组拆分数据帧
2)按列使用lapply:
@model VidlyApp.Models.Movie
@{
ViewBag.Title = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="col-lg-3">
<h4><strong>Released Date: </strong> @Model.ReleasedDate</h4>
</div>
<div class="col-lg-3">
<h4><strong>Added Date: </strong>@Model.DateAdded</h4>
</div>
由reprex package(v0.3.0)于2019-12-16创建