根据开始和结束索引(保存在两个向量中)并使用条件将 data.frame 拆分为较小的 data.frame
Posted
技术标签:
【中文标题】根据开始和结束索引(保存在两个向量中)并使用条件将 data.frame 拆分为较小的 data.frame【英文标题】:Split a data.frame into smaller data.frames, based on the start and end indices (held in two vectors) and using a condition 【发布时间】:2020-06-08 10:30:39 【问题描述】:我正在尝试编写一种算法,该算法允许将包含 100000 行的“ALL_DATA”数据帧划分为三列($Date、$Time、$Value),并根据标准划分为较小的 data.frames 和一系列开始和结束索引(包含在相同长度的“START”和“END”向量中(int [1: 500])。
例如,我用于计算的 data.frame 是:
ALL_DATA:
$Date $Time $Value
[1] 01/01/14 0:10:00 0.45
[2] 01/01/14 0:20:00 1.00
[3] 01/01/14 0:30:00 1.20
[4] 01/01/14 0:40:00 0.10
[5] 01/01/14 0:50:00 1.00
[6] 01/01/14 1:00:00 0.21
[7] 01/01/14 1:10:00 0.18
[8] 01/01/14 1:20:00 0.19
[9] 01/01/14 1:30:00 1.12
[10] 01/01/14 1:40:00 0.50
[11] 01/01/14 1:50:00 0.62
[12] 01/01/14 2:00:00 0.55
[13] 01/01/14 2:10:00 0.80
[14] 01/01/14 2:20:00 1.12
[15] 01/01/14 2:30:00 2.15
...
虽然我的两个向量包含引用 data.frame 的索引,例如这些:
START:
[1] 2
[2] 5
[3] 9
[4] 12
...
END:
[1] 3
[2] 8
[3] 11
[4] 15
...
此时,我想应用两个 START 和 END 索引之间的 $Value 元素之和为 >= 2 的条件,然后创建以下 data.frames:
SPLIT_DATA_FRAME "001": (the sum of the values is infact 2.20 > 2)
$Date $Time $Value
[2] 01/01/14 0:20:00 1.00
[3] 01/01/14 0:30:00 1.20
SPLIT_DATA_FRAME "002": (the sum of the values is infact 2.24 > 2)
$Date $Time $Value
[9] 01/01/14 1:30:00 1.12
[10] 01/01/14 1:40:00 0.50
[11] 01/01/14 1:50:00 0.62
SPLIT_DATA_FRAME "003": (the sum of the values is infact 4.62 > 2)
$Date $Time $Value
[12] 01/01/14 2:00:00 0.55
[13] 01/01/14 2:10:00 0.80
[14] 01/01/14 2:20:00 1.12
[15] 01/01/14 2:30:00 2.15
编辑:正如@Roland 所建议的那样,我尝试通过以下方式使用剪切和拆分功能:
split(ALL_DATA, cut(ALL_DATA$Value, breaks = unique(c(rbind(START, END)))))
cond <- sapply(split_ALL_DATA, function(DF) sum(DF$ALL_DATA$Value) >= 2)
split_ALL_DATA <- split_ALL_DATA[cond]
但我得到的结果是一组 data.frames 划分但不符合我的 START 和 END 索引向量,并且具有与原始 data.frame 相同的结构但内部没有值:
$`(2,3]`
[1] Date Time Value
<0 rows> (or 0-length row.names)
$`(3,5]`
[1] Date Time Value
<0 rows> (or 0-length row.names)
$`(5,8]`
[1] Date Time Value
<0 rows> (or 0-length row.names)
你能告诉我哪里错了吗?这是否取决于我的数据结构不仅包含数字数据,还包含日期和时间这一事实?非常感谢。
【问题讨论】:
使用cut
根据您的开始和结束索引将值分配给组,然后使用split
。
非常感谢您的帮助,所以在 for 循环中使用 cut 命令我会得到:for (i in 1: length (START)) check [i] <- cut (ALL_DATA $ ValUE, breaks = START [i]: END [i]) if (sum (check [i]> 4)) "create data.frame and save in .dat file"
我的程序是否正确?然后我在哪里插入拆分?再次感谢
根据上面的 ALL_DATA 输出和示例子集中的日期/时间变量,索引应该是行索引还是值本身的括号索引?前者与您的示例子集匹配。如果是后者,那么我最初的想法为什么您的子集数据框为空是因为您的Value
s 不够高,因此范围为空。
感谢您的评论,索引是行索引,它定义了一系列值以剪切主 data.frame,我手动检查了是否有足够高的值来满足条件。不幸的是,我无法得到任何结果,您能给我一些建议吗?非常感谢编辑:但是,我刚刚意识到我在上面的示例中插入了错误的条件,我立即更正,谢谢
因此,第一次拆分时,上面的第 2 行和第 3 行的值分别为 0.20 和 0.01。但是您的第一个条件拆分列出了 1.00 和 1.20 的值。除非我遗漏了什么,否则哪一个是正确的?
【参考方案1】:
根据对行索引的初始评论的回答,并使用类似的 3 部分方法(如 @Roland),以下应该是您想要的。
这将创建一个通用函数来返回从“开始”到“结束”的所有行(假设提供的元素是整数)
split_data <- function( start, end, dfr )
dfr[start:end,]
这将创建所有可用拆分的列表。
split.frames <- mapply(split_data,START,END,MoreArgs=list(dfr=ALL_DATA))
如果i
th 拆分满足所需条件,这将返回一个逻辑向量,其中i
th 元素等于TRUE。
cond <- sapply( split.frames, function(x)sum(x$Value)>=2 )
这仅返回满足条件的拆分。
split.frames <- split.frames[cond]
编辑#1
根据关于保存拆分的评论,最好使用 R 包 stringr
中的 str_pad()
函数来创建文件名,但这里是一个基本的 R 实现这应该适合你。
nchars <- nchar( length(split.frames) )
print.expr <- paste0("%0",nchars,"d")
for( i in 1:seq_along(split.frames) )
file.i <- paste0( sprintf(print.expr,i), ".dat" )
write.table( split.frames[[i]], file=file.i, sep="\t", row.names=FALSE )
不确定是否要在保存的输出中使用列名和/或行名,但我认为它们分别是 YES 和 NO。
【讨论】:
它有效,只是这样我得到一个唯一的列表,其中每三行(对应于日期、时间和值)我想创建一个单独的 data.frame 以便我可以将其保存在文本文件中。你能帮我把这个“大”列表变成data.frames列表吗?非常感谢您的帮助! 我认为我可以使用 for 循环构建 data.frame 并在每个循环中将其保存在一个文件中。这就是想法,尽管我必须了解如何一次考虑“split.frames”列表的三行,并且我仍然必须了解如何保存在文件中。FRAME=NULL for (k in 1:length(split.frames)) DATA <- split.frames[[k]] ORA <- split.frames[[k+1]] VALUE <- split.frames[[k+2]] FRAME <- rbind(FRAME, data.frame(DATA,ORA,VALUE)) "save FRAME in .txt"
虽然它没有包含在 OP 中,但您希望文件如何命名以及文件类型是什么?
我真的很感谢你的帮助@statsetw,我需要按数字顺序(001、002、003、004,...)调用 data.frames 并将它们保存在.dat 文件以制表符分隔。再次感谢。
我检查了您的答案是否正确,即使我错过了保存数据帧的最后一部分,即使我的问题中没有明确要求。再次感谢您的帮助。【参考方案2】:
我以iris
数据集(来自数据集包)为例。
head(iris)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#1 5.1 3.5 1.4 0.2 setosa
#2 4.9 3.0 1.4 0.2 setosa
#3 4.7 3.2 1.3 0.2 setosa
#4 4.6 3.1 1.5 0.2 setosa
#5 5.0 3.6 1.4 0.2 setosa
#6 5.4 3.9 1.7 0.4 setosa
假设我们要为 [-Inf, 5], (5, 6], (6, 7], (7, Inf] 中的每个萼片长度间隔创建一个 data.frame。那么我们可以这样做:
split_iris <- split(iris, cut(iris$Sepal.Length, breaks = c(-Inf, 5:7, Inf)))
然后你可以检查条件:
cond <- sapply(split_iris, function(DF) sum(DF$Petal.Width) > 20)
并将其用于子集:
split_iris <- split_iris[cond]
然后您可以遍历列表以导出到文件(使用for
循环或lapply
循环)。
【讨论】:
再次感谢您的帮助,我正在尝试使其适应我的情况,但我想请您澄清一下,我是否必须插入您在循环中指示的步骤?例如“split_iris [i]”并用作中断 = START [i]: END [i]?非常感谢 我问你这个问题,因为我有两个 500 元素的 START 和 END 向量,它们分别包含要剪切数据的开始和结束索引。非常感谢你的帮助,如果我问你很多事情,我很抱歉。 我试着像这样按照你的指示进行操作:split_ALL_DATA <- split(ALL_DATA, cut(ALL_DATA$Value, breaks = START:END))
问题是我必须插入包含索引的两个 START 和 END 向量,只有这两个向量的前两个索引在我希望为所有索引对剪切 data.frame 时使用,因此我认为我必须在 for 循环中插入您的指示。你能帮助我吗?非常感谢您,给您带来的不便深表歉意。
我不知道START
和END
包含什么。也许这个? split(ALL_DATA, cut(ALL_DATA$Value, breaks =unique(c(rbind(START, END))))
我已经修改了我最初的问题以使其更清晰,并包含了我的示例向量,希望能帮助您理解问题。感谢您的热心帮助。以上是关于根据开始和结束索引(保存在两个向量中)并使用条件将 data.frame 拆分为较小的 data.frame的主要内容,如果未能解决你的问题,请参考以下文章