规范化gnuplot中的直方图箱

时间:2011-04-26 07:09:28

标签: gnuplot histogram normalize bins

我正在尝试绘制一个直方图,其中的区域按照区域中元素的数量进行标准化。

我正在使用以下

binwidth=5
bin(x,width)=width*floor(x/width) + binwidth/2.0
plot 'file' using (bin($2, binwidth)):($4) smooth freq with boxes

获取基本直方图,但我希望每个bin的值除以bin的大小。我如何在gnuplot中进行此操作,或在必要时使用外部工具?

5 个答案:

答案 0 :(得分:9)

在gnuplot 4.4中,函数采用不同的属性,因为它们可以执行多个连续的命令,然后返回一个值(参见gnuplot tricks)这意味着你可以实际计算点数n,在gnuplot文件中,而不必事先知道它。此代码针对包含一列的文件“out.dat”运行:来自正态分布的n个样本列表:

binwidth = 0.1
set boxwidth binwidth
sum = 0

s(x)          = ((sum=sum+1), 0)
bin(x, width) = width*floor(x/width) + binwidth/2.0

plot "out.dat" u ($1):(s($1))
plot "out.dat" u (bin($1, binwidth)):(1.0/(binwidth*sum)) smooth freq w boxes

第一个绘图语句读取数据文件,并为每个点增加一次sum,绘制零。

第二个绘图语句实际上使用sum的值来标准化直方图。

答案 1 :(得分:8)

在gnuplot 4.6中,您可以按stats命令计算点数,这比plot快。实际上,您不需要这样的技巧s(x)=((sum=sum+1),0),而是在运行STATS_records后直接按变量stats 'out.dat' u 1计算数字。

答案 2 :(得分:3)

我将如何处理,使用以下命令从R生成n = 500个随机高斯变量:

Rscript -e 'cat(rnorm(500), sep="\\n")' > rnd.dat

我使用与你的相同的想法来定义标准化的直方图,其中y被定义为1 /(binwidth * n),除了我使用int而不是floor而我没有' t重新显示bin值。简而言之,这是smooth.dem演示脚本的快速改编,Janert的教科书中描述了类似的方法, Gnuplot in Action Chapter 13,第257页,免费提供)。您可以使用Gnuplot附带的random-points文件夹中的demo替换我的示例数据文件。请注意,我们需要将点数指定为Gnuplot,因为文件中的记录没有计数设施。

bw1=0.1
bw2=0.3
n=500
bin(x,width)=width*int(x/width)
set xrange [-3:3]
set yrange [0:1]
tstr(n)=sprintf("Binwidth = %1.1f\n", n) 
set multiplot layout 1,2
set boxwidth bw1
plot 'rnd.dat' using (bin($1,bw1)):(1./(bw1*n)) smooth frequency with boxes t tstr(bw1)
set boxwidth bw2
plot 'rnd.dat' using (bin($1,bw2)):(1./(bw2*n)) smooth frequency with boxes t tstr(bw2)

这是结果,有两个bin宽度

enter image description here

此外,这对于直方图来说确实是一种粗略的方法,R中可以使用更详细的解决方案。确实,问题是如何定义好的bin宽度,这个问题已在stats.stackexchange.com上讨论过:使用Freedman-Diaconis分箱规则不应该太难实现,尽管您需要计算四分位数范围。

以下是R将如何继续使用相同的数据集,默认选项(Sturges规则,因为在这种特殊情况下,这不会产生任何影响)和等间隔的bin,就像上面使用的那样。

enter image description here

使用的R代码如下:

par(mfrow=c(1,2), las=1)
hist(rnd, main="Sturges", xlab="", ylab="", prob=TRUE)
hist(rnd, breaks=seq(-3.5,3.5,by=.1), main="Binwidth = 0.1", 
     xlab="", ylab="", prob=TRUE)

通过检查调用hist()时返回的值,您甚至可以查看R的工作方式:

> str(hist(rnd, plot=FALSE))
List of 7
 $ breaks     : num [1:14] -3.5 -3 -2.5 -2 -1.5 -1 -0.5 0 0.5 1 ...
 $ counts     : int [1:13] 1 1 12 20 49 79 108 87 71 43 ...
 $ intensities: num [1:13] 0.004 0.004 0.048 0.08 0.196 0.316 0.432 0.348 0.284 0.172 ...
 $ density    : num [1:13] 0.004 0.004 0.048 0.08 0.196 0.316 0.432 0.348 0.284 0.172 ...
 $ mids       : num [1:13] -3.25 -2.75 -2.25 -1.75 -1.25 -0.75 -0.25 0.25 0.75 1.25 ...
 $ xname      : chr "rnd"
 $ equidist   : logi TRUE
 - attr(*, "class")= chr "histogram"

如果您愿意,可以使用R结果处理您的数据(尽管我建议直接使用R: - )。

答案 3 :(得分:2)

计算文件中数据点数的另一种方法是使用系统命令。如果您正在绘制多个文件,并且事先不知道点数,则证明这很有用。我用过:

countpoints(file) = system( sprintf("grep -v '^#' %s| wc -l", file) )
file1count = countpoints (file1)
file2count = countpoints (file2)
file3count = countpoints (file3)
...

countpoints函数避免计算以'#'开头的行。然后,您将使用已提到的函数绘制标准化直方图。

这是一个完整的例子:

n=100
xmin=-50.
xmax=50.
binwidth=(xmax-xmin)/n

bin(x,width)=width*floor(x/width)+width/2.0
countpoints(file) = system( sprintf("grep -v '^#' %s| wc -l", file) )

file1count = countpoints (file1)
file2count = countpoints (file2)
file3count = countpoints (file3)

plot file1 using (bin(($1),binwidth)):(1.0/(binwidth*file1count)) smooth freq with boxes,\
     file2 using (bin(($1),binwidth)):(1.0/(binwidth*file2count)) smooth freq with boxes,\
     file3 using (bin(($1),binwidth)):(1.0/(binwidth*file3count)) smooth freq with boxes
...

答案 4 :(得分:-2)

简单地

plot 'file' using (bin($2, binwidth)):($4/$4) smooth freq with boxes