我有一个大的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
我尝试了base
,dpylr
,purrr
但无法创建算法。
谢谢你的帮助。
试试这个:
找到“我”的值
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"
这是一种蛮力方法,应该是最容易提出但最不受欢迎的方法。无论如何,这里是:
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
}
}
这是使用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
})
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
我的解决方案
在@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秒。
我不确定编程风格,但现在这个解决方案适合我。
感谢您的所有建议。
一个纯粹的基础解决方案,我们正在建立一个“=="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