首页 > 解决方案 > 按 NA 行拆分多个数据帧中的数据帧

问题描述

  1. 问题解释:

我有一个数据框(参见代码中的 sim.Dat.file6),它以交替的方式具有数值和 NA 值。我想提取单个数据框中的数值并省略 NA 值。

  1. 我的数据:我模拟了这个数据集,以便在 R 中提供一个清晰且可重复的示例。
#simulated data set:

set.seed(101)
x <- rep(factor(c(sample(c("a","b",3.5,"d","e","f","a1","b1",2.4,"d=",0,"f3"), 6), rnorm(c(1:6), 0.5, 0.1))),3)
y <- rep(factor(c(sample(c("a","b",3.5,"d","e","f","a1","b1",2.4,"d=",0,"f3"), 6), rnorm(c(1:6), 200, 5))),3)
z1 <- rep(factor(c(sample(c("a","b",3.5,"d","e","f","a1","b1",2.4,"d=",0,"f3"), 6), rep(0,6))),3)
z2  <- rep(factor(c(sample(c("a","b",3.5,"d","e","f","a1","b1",2.4,"d=",0,"f3"), 6),  rep(0,6))),3)

sim.Dat.file <- data.frame(x, y, z1, z2) 

sim.Dat.file2 <- sim.Dat.file[,-c(3:4)]

sim.Dat.file3 <- data.frame(Wavelength = as.numeric(paste(sim.Dat.file2$y)), Absorption = as.numeric(paste(sim.Dat.file2$x)))

#omit false Wavelength values 
allNA <-function(x) {
  
  if(x>180 | is.na(x)==TRUE){
    
    return(x)
    
  }else{
    
    x<-NA
  }
}

sim.Dat.file4 <-as.data.frame(sapply(sim.Dat.file3$Wavelength, allNA))

#omit false Absorption values 

allNA <-function(x) {
  
  if((x<1 & x>0)| is.na(x)==TRUE){
    
    return(x)
    
  }else{
    
    x<-NA
  }
}

sim.Dat.file5 <-as.data.frame(sapply(sim.Dat.file3$Absorption, allNA))

sim.Dat.file6 <-data.frame(sim.Dat.file4, sim.Dat.file5)
colnames(sim.Dat.file6) <-c("Absorption", "Wavelength")


#strategy1 
splitFUN <- function(x) {
  
  split(x, is.na(x==TRUE))
  
}

sim.Dat.file7 <- lapply(sim.Dat.file6, splitFUN)

#different spectra are merged together

我现在卡住了,因为到目前为止,strsplitsplit 我的情况下不起作用。如果我使用split(df5, if.na(df5)==TRUE (如代码所示),我将 NA 值和数值分成两组(但我不能将它们分成单独的光谱并单独绘制每个光谱)。我将 NA 值更改为字符并尝试了 a strsplit,但这也不能正常工作。

#output of lapply-split extractet with dput
list(Absorption = list(`FALSE` = c(199.033310175013, 195.751226298331, 
200.292327489247, 195.91164822062, 189.748460921802, 199.181221670293, 
199.033310175013, 195.751226298331, 200.292327489247, 195.91164822062, 
189.748460921802, 199.181221670293, 199.033310175013, 195.751226298331, 
200.292327489247, 195.91164822062, 189.748460921802, 199.181221670293
), `TRUE` = c(NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_)), 
    Wavelength = list(`FALSE` = c(0.53107692173136, 0.61739662875627, 
    0.561878985562597, 0.488726568524579, 0.591702828951271, 
    0.477674063537274, 0.53107692173136, 0.61739662875627, 0.561878985562597, 
    0.488726568524579, 0.591702828951271, 0.477674063537274, 
    0.53107692173136, 0.61739662875627, 0.561878985562597, 0.488726568524579, 
    0.591702828951271, 0.477674063537274), `TRUE` = c(NA_real_, 
    NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, 
    NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, 
    NA_real_, NA_real_, NA_real_, NA_real_, NA_real_)))
  1. 数据转换的目的:

我想自动从数据集中提取数值。提取的值应在数据框中一个接一个地添加,或者每组数字提取值应保存在单独的数据框中。在这种情况下,最佳输出将是

output.data.frame <- data.frame(spectra1= sim.Dat.file6[7:12,], spectra2= sim.Dat.file6[19:24,], spectra3= sim.Dat.file6[31:36,])
output.data.frame
   spectra1.Absorption spectra1.Wavelength spectra2.Absorption spectra2.Wavelength spectra3.Absorption
7             199.0333           0.5310769            199.0333           0.5310769            199.0333
8             195.7512           0.6173966            195.7512           0.6173966            195.7512
9             200.2923           0.5618790            200.2923           0.5618790            200.2923
10            195.9116           0.4887266            195.9116           0.4887266            195.9116
11            189.7485           0.5917028            189.7485           0.5917028            189.7485
12            199.1812           0.4776741            199.1812           0.4776741            199.1812
   spectra3.Wavelength
7            0.5310769
8            0.6173966
9            0.5618790
10           0.4887266
11           0.5917028
12           0.4776741

标签: rdataframe

解决方案


我认为以下内容以一种非常简单的方式完成了您想要的操作。

res_wave <- sim.Dat.file3$Wavelength[!is.na(sim.Dat.file3$Wavelength)]
res_abso <- sim.Dat.file3$Absorption[!is.na(sim.Dat.file3$Absorption)]
result <- data.frame(res_wave, res_abso)
> head(result)
  res_wave  res_abso
1   0.0000 2.4000000
2 199.0333 0.5310769
3 195.7512 0.6173966
4 200.2923 0.5618790
5 195.9116 0.4887266
6 189.7485 0.5917028

NA 值使用 idiom 过滤掉x[!is.na(x)]。顺便说一句,我不清楚你想用你的功能实现什么

testfunction <-function(x) {
  if((x<1 & x>0)| is.na(x)){
    print("condition is true on first element")
    return(x)
  }else{
    print("condition is false on first element")
    x<-NA
  }
}
testdata1 <- c(0.5,1,NA)
testdata2 <- c(999,1,NA)
testfunction(testdata1)
# > testfunction(testdata1)
# [1] "condition is true on first element"
# [1] 0.5 1.0  NA
# Warning message:
#   In if ((x < 1 & x > 0) | is.na(x)) { :
#       the condition has length > 1 and only the first element will be used

# testfunction(testdata2)
# [1] "condition is false on first element"
# Warning message:
#   In if ((x < 1 & x > 0) | is.na(x)) { :
#       the condition has length > 1 and only the first element will be used

如果其第一个元素满足您的条件,此函数将返回作为参数传递的相同向量(其所有原始值) 。

如果第一个元素不满足您的条件,它将不返回任何内容,只会执行x<-NA将更改to中的所有值。xNA

除了在这种情况下它不会更改对象,因为您是x在函数环境内部而不是在全局环境中更改。正如您在下面看到的,data2保持不变,因为它只是在函数内更改。

> testdata2
[1] 999   1  NA

为了在.Globalenv()函数中修改 from 中的对象,您可以使用<<-而不是在<-这里,但我认为问题在于您不知道 R 的矢量化方面。

如果 data1 是vector,data1 > 0将返回一个,长度与 相同的值的向量。但该语句只考虑了这些布尔值中的第一个。TRUEFALSEdata1if

尝试查看我的解决方案并了解它是如何工作的。如您所见,R 中的矢量化允许您绕过对许多循环和函数的需求。


推荐阅读