R改变数据帧列值与前一列的比较

时间:2018-03-29 00:11:01

标签: r dataframe multiple-columns apply

我有一个大数据库,但是为了这个练习,我们可以使用这个:

    c-1    c-2   c-3  c-4  c-5 c-6  
   1-14  14-29  NA    NA   NA  NA
   60-90  CF    CF    CF   CF  CF
    C     1-14  14-29 CF   NA  NA
   60-90  CF    CF    CF   NA  NA

我想要的是将所有在前一列中获得CF的列更改为HF,这样看起来像这样:

   c-1    c-2   c-3  c-4  c-5 c-6  
   1-14  14-29  NA    NA   NA  NA
   60-90  CF    HF    HF   HF  HF
    C     1-14  14-29 CF   NA  NA
   60-90  CF    HF    HF   NA  NA

我试图通过这样的应用来做到这一点,但它没有正常工作

function_a <- function (x) {ifelse(df[,i]=="CF" & df[,i-1]=="CF", "HF", df[,i])}    
new_df<- as.data.frame(lapply(length(df):1, function_a))

请记住,如果前一列不是CF,我想保留原始值,有没有简单的方法可以做到这一点?在R基地?

3 个答案:

答案 0 :(得分:4)

我喜欢这个问题,因为直接将它看作是各种各样的滚动应用,但不是zoo::rollapply意义上的(虽然它也可以在那里管理)。我在谈论使用Reduce(..., accumulate=TRUE)

您的数据:

dat <- data.frame(
  c1 = c('1-14','60-90','C','60-90'),
  c2 = c('14-29','CF','1-14','CF'),
  c3 = c(NA,'CF','14-29','CF'),
  c4 = c(NA,'CF','CF','CF'),
  c5 = c(NA,'CF',NA,NA),
  c6 = c(NA,'CF',NA,NA),
  stringsAsFactors = FALSE
)

我正在添加逻辑以检查上一列中的"HF",否则您将获得交替"CF" / "HF"。我推断,无论以前的列如何,NA都应始终为NA,因为这就是您的示例的外观。 (这个假设很容易被删除。)

func <- function(a, b) ifelse(! is.na(a) & ! is.na(b) & a %in% c("CF","HF"), "HF", b)

默认情况下,Reduce仅返回最后一列的结果。使用accumulate=TRUE,它返回每个调用的结果(加上第一列),我们将使用它来重新填充相同大小的帧。

df[] <- Reduce(func, df, right=FALSE, accumulate=TRUE)
df
#      c1    c2    c3   c4   c5   c6
# 1  1-14 14-29  <NA> <NA> <NA> <NA>
# 2 60-90    CF    HF   HF   HF   HF
# 3     C  1-14 14-29   CF <NA> <NA>
# 4 60-90    CF    HF   HF <NA> <NA>

答案 1 :(得分:3)

另一个建议的解决方案是转置矩阵,将矩阵滞后1行,然后检查滞后矩阵中的CF和转置矩阵中的CF,最后转置回来得到所需的输出:

tdat <- t(dat)
lagged <- rbind(matrix(NA_character_, ncol=nrow(dat)), tdat[-nrow(tdat),])
tdat[lagged=="CF" & tdat=="CF"] <- "HF"
res <- t(tdat)
res

数据:

dat <- read.table(text="c-1    c-2   c-3  c-4  c-5 c-6  
1-14  14-29  NA    NA   NA  NA
60-90  CF    CF    CF   CF  CF
C     1-14  14-29 CF   NA  NA
60-90  CF    CF    CF   NA  NA", header=TRUE, check.names=FALSE)

答案 2 :(得分:3)

使用与原始数据大小相同的矩阵,查找第一次出现后连续出现的"CF"个单元格:

sel <- dat == "CF" & (!is.na(dat))
dat[col(dat) > max.col(sel, "first") & sel] <- "HF"
dat
#    c-1   c-2   c-3  c-4  c-5  c-6
#1  1-14 14-29  <NA> <NA> <NA> <NA>
#2 60-90    CF    HF   HF   HF   HF
#3     C  1-14 14-29   CF <NA> <NA>
#4 60-90    CF    HF   HF <NA> <NA>

使用@ r2evans'dat对象。