使用多个文件在R中分区值

时间:2015-02-17 16:36:16

标签: r text-files binning

因此,我将多个文本文件中包含的值分箱到设定范围时遇到了一些问题。我已经在网上查看了各种软件包,并且遇到了可以bin值的sm,你也可以指定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等,所有这些值的中位数用于表示仓,第一个仓的中值为1,第二个,第三个,第三个(我知道在这个例子中,取中值可能看起来毫无意义,但我得到的数据是有道理的)

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

1 个答案:

答案 0 :(得分:3)

有几种方法可以做到,我将提供一种使用基本功能的方法。 (另一种方法是使用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是因为垃圾箱只包含范围的一侧(默认值:右侧),因此最小值不会被分箱。它还确保箱子在圆形边界上。

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