R data.frame操作:在特定列之后转换为NA

问题描述 投票:0回答:6

我有一个大的data.frame,我需要一些基于行的转换。如果列中有特定字符,我的目的是将行中的所有值转换为NA

例如,我从我的真实数据集中提供了很少的样本:

sample_df <- data.frame( a = c("V","I","V","V"), b = c("I","V","V","V"), c = c("V","V","I","V"),  d = c("V","V","I","V"))


result_df <- data.frame( a = c("V","I","V","V"), b = c("I",NA,"V","V"), c = c(NA,NA,"I","V"), d = c(NA,NA,NA,"V"))

作为sample_df中的一个例子首先我想在第一个“I”之后将所有值都转换为NA

Sample data.frames

我尝试了basedpylrpurrr但无法创建算法。

谢谢你的帮助。

r dataframe dplyr apply base
6个回答
1
投票

试试这个:

找到“我”的值

I_true<-sample_df=="I"
I_true
         a     b     c     d
[1,] FALSE  TRUE FALSE FALSE
[2,]  TRUE FALSE FALSE FALSE
[3,] FALSE FALSE  TRUE  TRUE
[4,] FALSE FALSE FALSE FALSE

找到第一个“我”看到的位置

out<-t(apply(t(I_true),2,cumsum))
    out
     a b c d
[1,] 0 1 1 1
[2,] 1 1 1 1
[3,] 0 0 1 2
[4,] 0 0 0 0

替换所需的值

 output<-out
 output[out>=1]<-NA 
 output[output==0]<-"V"
 output[I_true]<-"I"
 output[out>=2]<-NA 

你的输出

output
     a   b   c   d  
[1,] "V" "I" NA  NA 
[2,] "I" NA  NA  NA 
[3,] "V" "V" "I" "I"
[4,] "V" "V" "V" "V"

例2:

sample_df <- data.frame( a = c("V","I","I","V"), b = c("I","V","V","V"), c = c("V","V","I","V"), d = c("V","V","I","V"))
sample_df
  a b c d
1 V I V V
2 I V V V
3 I V I I
4 V V V V
output
     a   b   c   d  
[1,] "V" "I" NA  NA 
[2,] "I" NA  NA  NA 
[3,] "I" NA  NA  NA 
[4,] "V" "V" "V" "V"

0
投票

这是一种蛮力方法,应该是最容易提出但最不受欢迎的方法。无论如何,这里是:

df <- data.frame( a = c("V","I","V","V"), b = c("I","V","V","V"), c = c("V","V","I","V"),  d = c("V","V","I","V"), stringsAsFactors=FALSE)
rowlength<-length(colnames(df))
for (i in 1:length(df[,1])){
   if (any(as.character(df[i,])=='I')){
      first<-which(as.character(df[i,])=='I')[1]+1
      df[i,first:rowlength]<-NA
   }
}

0
投票

这是使用ddply包中的plyr的可能答案

ddply(sample_df,.(a,b,c,d), function(x){
  idx<-which(x=='I')[1]+1 #ID after first 'I'
  if(!is.na(idx)){    #Check if found
    if(idx<=ncol(x)){  # Prevent out of bounds
      x[,idx:ncol(x)]<-NA
    }

  }
  x
})

0
投票

plyr方法:

plyr::adply(sample_df, 1L, function(x) { 
  if (all(x != "I")) 
    return(x)
  x[1L:min(which(x == "I"))]
})

你必须使用if因为x[min(which(x == "I"))]将返回没有至少一个numeric(0)的行的I


0
投票

我的解决方案

在@Julien Navarre推荐之后,我首先创建了toNA()函数:

toNA <- function(x) {

  temp <- grep("INVALID", unlist(x)) # which can be generalized for any string

  lt <- length(x)
  loc <- min(temp,100)+1 #100 is arbitrary number bigger than actual column count

  #print(lt) #Debug purposes 

  if( (loc < lt+1) ) {
    x[ (loc):(lt)] <-NA
  }

  x

} 

首先,我尝试使用plyr::adply()purrrlyr::by_row()函数来应用我的toNA()函数我的data.frame,它有超过300万行。

两者都很慢。 (对于1000行,它们分别需要9秒和6秒)。使用简单的function(x) x,这些方法也很慢。我不确定什么是开销。

所以我尝试了base::apply()功能:( result是我的数据集)

as.tibble(t(apply(result, 1,  toNA ) ))

1000行只需0.2秒。

我不确定编程风格,但现在这个解决方案适合我。

感谢您的所有建议。


0
投票

一个纯粹的基础解决方案,我们正在建立一个“=="I"或不是”的布尔矩阵,然后我们可以找到我们的NAs必须放置的位置:

result_df <- sample_df
is.na(result_df) <- t(apply(sample_df == "I",1,function(x) cumsum(cumsum(x)))) >1

result_df 
#   a    b    c    d
# 1 V    I <NA> <NA>
# 2 I <NA> <NA> <NA>
# 3 V    V    I <NA>
# 4 V    V    V    V
© www.soinside.com 2019 - 2024. All rights reserved.