【问题标题】:Binning values in R with multiple files将 R 中的值与多个文件合并
【发布时间】:2015-02-17 16:36:15
【问题描述】:

所以我在将多个文本文件中包含的值合并到设定范围时遇到了一个小问题。我在网上查看了各种包,发现 sm 可以对值进行 bin 处理,您也可以像这样指定 bin 范围:-

xb <- binning(x, breaks=seq(-4,4,by=0.5))

但我在实现这一点时遇到了一些问题。我无法指定上限,因为我不知道上限是多少(文件有数千个从仪器获得的值),我有 25 个文件,每个文件包含数千个值,我需要将它们全部装箱同时(我需要随后取所有这些分箱值的中值)并且我在开始阅读文本文件时遇到了麻烦。我执行:-

read.table("foobar.txt", sep=",")

只读取一个文本文件,因为所有值都用“,”分隔,但它似乎无法处理这个问题。此外,我希望能够将给定范围为 0.0005 的值分箱(例如,值在 200.0000 - 200.0005、200.0005 - 200.0010 等之间分箱)

我使用的文本文件是 .txt,其值由逗号分隔并包含数千个值。这个想法是我将值分组到设定范围内的组中,然后取代表该特定 bin 的那些值的中值。例如,如果我有值 1,1,2,3,3,4,5,5,6,7,7,9,10 并将 bin 的范围设置为 2,那么第一个 bin 将包含1,1,2,第二个 3,3,4,第三个 5,5,6 等,所有这些值的中值被用来表示 bin,第一个 bin 的中值为 1,第二个 3,第三个 5(我知道在这个例子中,取中值似乎毫无意义,但根据我拥有的数据,它是有道理的)

有没有一种方法可以读取多个值的文本文件并按照我描述的方式同时处理它们?有没有这样的包,我可以看一下手册?任何建议或提示将不胜感激!

【问题讨论】:

  • 仅供参考,基础 R 中有 ?cut 用于分箱值
  • 道歉我应该提到我想在一个设定的范围内分箱值(对于我正在做的事情,我想要分箱 0.0005 内的值,所以 200.0000 - 200.0005 等)
  • 我将编辑上面的文本以包含所有这些,但这些文件都是 .txt 文件,因为我有太多的 .csv 值并且它的形式是 x1、x2、x3(所以如 104、204、223.3432) 等数千次。基本上我的目标是将所有值分组,然后当所有值都在给定范围内分组时,如果有意义的话,我想取落入给定箱的原始非分箱值的所有这些值的中值.因此,例如,如果我有 1、2、4、5、10,并且我将它们的范围设置为 2,因此 1 和 2 在一起,然后是 4 和 5,然后是 10,则取它们的中位数

标签: r text-files binning


【解决方案1】:

有几种方法可以做到这一点,我将提供一种使用基函数的方法。 (另一种方法是使用dplyr,也非常适合这种情况。但是,基本示例应该足够简单。)

生成数据

(这里只是因为我们没有您的任何数据。)

n <- 10
for (ii in 1:3) {
    dat <- runif(n)
    writeLines(paste(dat, collapse = ','),
               con = sprintf('user2062207-file%s.txt', ii))
}
readLines('user2062207-file1.txt')
## [1] "0.929472318384796,0.921938128070906,0.707776406314224,0.236701443558559,0.271322417538613,0.388766387710348,0.422867075540125,0.324589917669073,0.92406965768896,0.171326051233336"

读取数据

假设您有一个查找文件的简单模式,您将从这里开始。

fnames <- list.files(pattern = 'user2062207-file.*.txt')
allData <- unlist(sapply(fnames, read.table, sep = ','))
allRange <- range(allData)
df <- data.frame(x = allData)
head(df)
##           x
## 1 0.9294723
## 2 0.9219381
## 3 0.7077764
## 4 0.2367014
## 5 0.2713224
## 6 0.3887664
dim(df)
## [1] 30  1

设置垃圾箱

下面的 {floor,ceiling} +/- binSize 是因为 bin 仅包含范围的一侧(默认值:右侧),因此不会对最小值进行 bin 。它还确保 bin 位于圆形边界上。

binSize <- 0.05
allBins <- seq(floor(allRange[1] / binSize) * binSize,
               ceiling(allRange[2] / binSize) * binSize,
               by = binSize)
## bin the data
df$bin <- cut(df$x, breaks = allBins)
head(df)
##           x        bin
## 1 0.9294723 (0.9,0.95]
## 2 0.9219381 (0.9,0.95]
## 3 0.7077764 (0.7,0.75]
## 4 0.2367014 (0.2,0.25]
## 5 0.2713224 (0.25,0.3]
## 6 0.3887664 (0.35,0.4]

每个 Bin 的统计数据

sapply(levels(df$bin), function(lvl) median(df$x[df$bin == lvl], na.rm = TRUE))
##   (0,0.05] (0.05,0.1] (0.1,0.15] (0.15,0.2] (0.2,0.25] (0.25,0.3] (0.3,0.35] 
## 0.03802277         NA 0.11528715 0.18195392 0.22918094 0.27132242 0.33626971 
## (0.35,0.4] (0.4,0.45] (0.45,0.5] (0.5,0.55] (0.55,0.6] (0.6,0.65] (0.65,0.7] 
## 0.38009637 0.42184059         NA 0.53826028 0.57820253 0.64165116 0.67825992 
## (0.7,0.75] (0.75,0.8] (0.8,0.85] (0.85,0.9] (0.9,0.95]   (0.95,1] 
## 0.74243926         NA 0.80759621 0.88974267 0.92406966 0.95691077 

这是一个可以有许多其他选择的领域。例如,基本函数by 可以工作,尽管处理它的数据结构并不总是直观的,即使函数调用本身很容易阅读:

head(by(df$x, df$bin, median, na.rm = TRUE))
## df$bin
##   (0,0.05] (0.05,0.1] (0.1,0.15] (0.15,0.2] (0.2,0.25] (0.25,0.3] 
## 0.03802277         NA 0.11528715 0.18195392 0.22918094 0.27132242 

您也可以轻松使用dplyr。这个例子以原来的allDataallBins开头:

library(dplyr)
data.frame(x = allData) %>%
    mutate(bin = cut(x, breaks = allBins)) %>%
    group_by(bin) %>%
    summarise(median(x))
## Source: local data frame [17 x 2]
##           bin  median(x)
## 1    (0,0.05] 0.03802277
## 2  (0.1,0.15] 0.11528715
## 3  (0.15,0.2] 0.18195392
## 4  (0.2,0.25] 0.22918094
## 5  (0.25,0.3] 0.27132242
#### ..snip..

第一个示例保留空箱,而其他方法不知道空箱。可能还有其他使用 bydplyr 的方法,包括这些空垃圾箱,但这似乎就足够了。

编辑

聊了一会,确定数据的范围太宽了,bin宽度为0.0005。设计了一个更好的解决方案。 (没有样本数据可提供,抱歉,不是我要提供的......)我将使用随机数据来模拟这个过程:

set.seed(42)
x <- 5e7 * runif(5e5)

library(dplyr)
binSize <- 0.0005
df <- data.frame(dat = sort(x))
df$bin <- floor(df$dat / binSize) * binSize
head(df)
##         dat       bin
## 1  410.9577  410.9575
## 2  456.6275  456.6270
## 3  552.3674  552.3670
## 4  875.4898  875.4895
## 5 1018.6806 1018.6805
## 6 1102.2436 1102.2435
system.time(results <- df %>% group_by(bin) %>% summarize(med = median(dat)))
##    user  system elapsed 
##   12.08    0.00   12.11 
head(results)
## Source: local data frame [6 x 2]
##         bin       med
## 1  410.9575  410.9577
## 2  456.6270  456.6275
## 3  552.3670  552.3674
## 4  875.4895  875.4898
## 5 1018.6805 1018.6806
## 6 1102.2435 1102.2436

【讨论】:

  • 太棒了,我现在会尝试实现它,并会尽快回复您,但非常感谢您!
  • 很抱歉花时间回复您,我拥有的文件非常大,它仍在处理 allData
  • 我并不感到惊讶,单行上包含大量数据的文件可能会出现问题。如果文件那么大,也许您应该考虑另一种读取它们的方法(代替read.table)。我没有足够的经验来推荐任何人,但之前有几个关于该主题的问题(例如,172777211782084)。
  • 抱歉,我已经完成了数据的加载,但是我在分箱数据时遇到了问题。我要求将所有值分箱在 0.0005 之间,因此我将 binSize 设置为该值,但是在执行 allBins 部分时出现以下错误:- seq.default(floor(allRange[1]/binSize) * binSize, ceiling (allRange[2]/binSize) * : 'by' 参数太小了
  • allRange 的值是多少?只有当你变得非常大(在 Windows 上超过 2,147,483,647)时才会发生这种情况。
猜你喜欢
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多