Нормализация бинов гистограммы в gnuplot - PullRequest
6 голосов
/ 26 апреля 2011

Я пытаюсь построить гистограмму, чьи ячейки нормализованы по количеству элементов в ячейке.

Я использую следующее

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

, чтобы получить базовую гистограмму, но я хочу, чтобы значение каждого бина было разделено на размер бина. Как я могу сделать это в gnuplot или при необходимости использовать внешние инструменты?

Ответы [ 5 ]

9 голосов
/ 21 декабря 2011

В gnuplot 4.4 функции принимают другое свойство: они могут выполнять несколько последовательных команд, а затем возвращать значение (см. хитрости gnuplot ). Это означает, что вы можете фактически рассчитать количество точек. , 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

Первый оператор заговора считывает файл данных и увеличивает сумму по одному разу для каждой точки, составляя ноль.

Второй оператор заговора фактически использует значение суммы для нормализации гистограммы.

8 голосов
/ 24 октября 2012

В gnuplot 4.6 вы можете посчитать количество баллов командой stats, которая быстрее, чем plot. На самом деле, вам не нужен такой трюк s(x)=((sum=sum+1),0), а сразу подсчитайте число по переменной STATS_records после выполнения stats 'out.dat' u 1.

3 голосов
/ 10 мая 2011

Вот как бы я это сделал, используя n = 500 случайных гауссовых переменных, сгенерированных из R, с помощью следующей команды:

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

Я использую ту же идею, что и вы, для определения нормализованной гистограммы, где yопределяется как 1 / (binwidth * n), за исключением того, что я использую int вместо floor, и я не перецентрировал значение bin.Короче говоря, это быстрая адаптация из демонстрационного скрипта smooth.dem , и аналогичный подход описан в учебнике Джанерта, Gnuplot в действии ( Глава 13 , стр. 257, в свободном доступе).Вы можете заменить мой пример файла данных на random-points, который доступен в папке demo, поставляемой с Gnuplot.Обратите внимание, что нам нужно указать количество точек в 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)

Вот результат с шириной двух бинов

enter image description here

Кроме того, это действительно грубый подход к гистограмме, и более сложные решения легко доступны в R. Действительно, проблема заключается в том, как определить хорошую ширину ячейки, и эта проблема уже обсуждалась на stats.stackexchange.com : использование правила Freedman-Diaconis не должно быть слишком сложным для реализации, хотя вам потребуется вычислить интервал квартиля.

Вот какR продолжит работу с тем же набором данных, с опцией по умолчанию (правило Sturges, потому что в данном конкретном случае это не будет иметь значения) и с одинаковым интервалом, как те, которые использовались выше.

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)

Вы даже можете посмотреть, как R выполняет свою работу, проверив значения, возвращаемые при вызове hist():

> 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 для обработки ваших данных с Gnuplot, если хотите (хотя я бы рекомендовал использовать R напрямую: -).

2 голосов
/ 01 мая 2013

Другим способом подсчета количества точек данных в файле является использование системной команды. Это оказывается полезным, если вы строите несколько файлов и заранее не знаете количество точек. Я использовал:

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
...
0 голосов
/ 15 декабря 2016

Просто

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