将R强制绘制直方图为概率(相对频率)

19

我在绘制概率密度直方图方面遇到了麻烦。

我希望所有区间的总和都等于1,这样可以更容易地比较数据集。但是不知为何,每当我指定分割点(默认为4或其他值),它就不再绘制概率密度而是绘制频数分布。

hist(data[,1], freq = FALSE, xlim = c(-1,1), breaks = 800)
我该如何更改这一行?我需要一个概率分布和大量的箱子。(我有600万个数据点)
这在 R 帮助文件中,但我不知道如何覆盖它:
freq 逻辑值; 如果为 TRUE,则直方图图形是结果中 counts 部分的表示;如果为 FALSE,则绘制概率密度,组成部分 density (使直方图的总面积为1)。如果并且没有指定 probability,则默认为 TRUE。
谢谢
编辑: 细节
我的图形超过了 1,如果这是概率就相当令人困惑。现在我明白这与箱子宽度有关。我更多地想让每个箱子价值 1 分钟,同时仍然有很多箱子。换句话说,除非直接位于 1.0,并且所有其他箱子都为 0.0,否则不应该有任何箱子高度超过 1.0。目前,我的箱子在 15.0 左右形成了一个圆顶。
编辑: 按%点高度
@Dwin : 那么我该如何绘制概率?我意识到由于 x 轴上的单位,取积分仍将给我 1.0,但这不是我想要的。比如说,我有100个点,其中5个点落在第一个箱子里,那么那个箱子的高度应该为0.05。这就是我想要的。我做错了吗?还有其他方法可以实现这个目的吗?
我知道我有多少点。有没有办法将频率直方图中每个箱子计数除以这个数字?

3
这是一个密度,而不是概率。(澄清一下:在某些点上,xf(x)的积分大于1.0并不意味着f(x)在所有x处都必须小于1.0。无论是有限范围还是无限范围内,xf(x)的积分都小于或等于1.0。) - IRTFM
6个回答

46
回应要求绘制概率而不是密度的请求:
h <- hist(vec, breaks = 100, plot=FALSE)
h$counts=h$counts/sum(h$counts)
plot(h)

太棒了!我不知道你可以将直方图放入变量中,然后获取计数。 - SwimBikeRun
1
+1 很好。关键是 R 默认不会生成相对频率(概率)直方图。 - Assad Ebrahim
1
然而,如果您自己指定了断点,特别是非均匀断点,则R默认显示密度而不是计数(频率)。为了解决这个问题,在绘图之前需要添加另一行:plot(h, freq=TRUE)。建议将此内容添加到您的答案中,以使其完全通用。 - Assad Ebrahim
如果我正确理解了你的建议,它似乎概述了一种替代方法。如果它确实有用,那么也许你应该撰写自己的答案来展示它的价值。(目前看来,它对我来说似乎不会成功。) - IRTFM

3

默认的断点数量约为log2(N),其中N是您的情况下的600万,因此应该是22。如果您只看到4个断点,那可能是因为您在调用中使用了xlim。这不会改变底层直方图,它只影响绘制的部分。如果你这样做:

h <- hist(data[,1], freq=FALSE, breaks=800)
sum(h$density * diff(h$breaks))

你应该得到一个结果为1。


数据的密度与其单位有关,因此您要确保“没有任何箱子高度超过1.0”实际上是有意义的。例如,假设我们有一堆以英尺为单位的测量值。我们将测量值的直方图绘制为密度图。然后,我们将所有测量值转换为英寸(通过乘以12),并进行另一个密度直方图。即使数据本质上相同,密度的高度也将是原始高度的1/12。同样,您可以通过将所有数字乘以15来使您的箱子高度小于1。

值1.0是否具有某种重要意义?


1
是的,1.0非常有意义。我想要查看一个bin中占比的点的百分比。问题在于手动设置断点会破坏hist()函数的freq=FALSE部分:这个部分通常可以让它成为一个百分比直方图。我的不同图必须先呈现概率图,否则比例就无法匹配,也无法进行比较。 - SwimBikeRun

2

你确定吗?这对我有用:

> vec <- rnorm(6000000)
> 
> h <- hist(vec, breaks = 800, freq = FALSE)
> sum(h$density)
[1] 100
> unique(zapsmall(diff(h$breaks)))
[1] 0.01

把最后两个结果相乘,你会得到一个概率密度总和为1的结果。记住这里的箱子宽度很重要。

这是与……

> sessionInfo()
R version 3.0.1 RC (2013-05-11 r62732)
Platform: x86_64-unknown-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=en_GB.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_GB.UTF-8        LC_COLLATE=en_GB.UTF-8    
 [5] LC_MONETARY=en_GB.UTF-8    LC_MESSAGES=en_GB.UTF-8   
 [7] LC_PAPER=C                 LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] tools_3.0.1

嗯,我的图形超过了1,如果它是一个概率,那就相当令人困惑。我现在明白它与箱宽有关了。我更多地想让每个箱子的值都为1,同时还要有很多箱子。换句话说,除非直接在1.0处且所有其他箱子都为0.0,否则不应该有任何箱子超过1.0。 - SwimBikeRun
2
错误。这不是一个概率。考虑到它已经被问了很多次,这可能应该被提升为常见问题解答。 - IRTFM
1
DWin的评论很有帮助。DWin所说的密度通常被称为概率密度,或者更严格地说,密度估计是针对变量的概率密度函数。如果您想了解更多信息,请阅读维基百科上的密度估计概率密度函数 - Gavin Simpson
@Dwin:那么我该如何绘制概率图呢?我意识到对积分的计算仍将得到1.0,因为x轴上的单位,但这不是我想要的结果。比如说,如果我有100个数据点,其中5个落在第一个区间内,那么该区间的高度应该为0.05。这就是我想要的结果。我做错了吗?还有其他方法可以实现吗? - SwimBikeRun
在处理连续函数时,你不能谈论"f(x)在x=2的概率",因为从2到2的积分将始终为0。你只能谈论非零长度区间上的概率。对于累积概率函数,你可以绘制在所选特定x序列处求得的cumsum(f(x))/sum(f(x)。对于所选区间内的概率,你可以使用cx <- cut(x, breaks)table(cx),并将该矩阵除以sum(table(cx)) - IRTFM
显示剩余2条评论

1
set.seed(0)

# Define a fair coin:
coin = c(1,0)

# We tossed the coin 10 times and counted the number of heads. Repeat the experiment 20000 times.
n = 20000   # Number of experiments
flips = 10  # Number of coin flips in each experiment.

heads = colSums(replicate(n, sample(coin, flips, replace = T))) # Counts of heads in each experiment.

# The breaks are the number of possible outcomes: flips + 1

h = hist(heads, breaks = sort(unique(heads)), freq=F, 
          border=F, main = 'Histogram counts of heads',
          col=rgb(0.3,0.8,0.8,0.6), ylab='Probability', 
          xlab =  'No. of heads in 10 flips fair coin')

enter image description here


如果有人看到这里能够帮到你,可以查看以下解决方案:
set.seed(0)

d = rnorm(1000)
n = 1000
d = rnorm(n)

histogram = hist(d, breaks=10, prob=T, border=F)
unique(diff(histogram$breaks)) # Because the size of the base of the rectangles is 0.5, the height will be double the tru relative freq.

# The fix. Notice that I redefine the histogram simply to show how simple the call is with with this fix.
h = hist(d, plot=F)
bp = barplot(h$counts/sum(h$counts), border=F)
axis(1, at=c(bp), labels=h$mids)
title(ylab="Relative Frequency")

感谢这个答案

0

我注意到,在直方图中

密度 = 相对频率 / 对应的箱宽

例子1:

nums = c(10, 41, 10, 28, 22,  8, 31,  3,  9,  9)

h2 = hist(nums, plot=F)

rf2 = h2$counts / sum(h2$counts)

d2 = rf2 / diff(h2$breaks)

h2$density

[1] 0.06 0.00 0.02 0.01 0.01

d2

[1] 0.06 0.00 0.02 0.01 0.01

示例2:

nums = c(10, 41, 10, 28, 22,  8, 31,  3,  9,  9)

h3 = hist(nums, plot=F, breaks=c(1,30,40,50))

rf3 = h3$counts / sum(h3$counts)

d3 = rf3 / diff(h3$breaks)

h3$density

[1] 0.02758621 0.01000000 0.01000000

d3

[1] 0.02758621 0.01000000 0.01000000

-1

R 似乎有一个错误或其他问题。如果您在 data.frame(只有1列)中具有离散数据,并对其调用 hist(DF,freq=FALSE),则相对密度将是错误的(总和大于1)。据我所知,这不应该发生。

解决方案是首先对对象调用 unlist()。这样可以修复绘图。 enter image description hereenter image description here (我也更改了文本,数据来自http://www.electionstudies.org/studypages/anes_timeseries_2012/anes_timeseries_2012.htm


3
我强烈怀疑这不是一个漏洞,而是由于箱子的宽度小于1,因此您需要使用sum(dens)*delta,而不仅仅是sum(dens) - Ben Bolker
3
我认为这不是一个 bug,而是你对 hist() 函数的误解。你可以尝试使用 prop.table(table(x)) 函数。 - Ben Bolker
那么,为什么使用unlist()后它能正常工作呢?plot(prop.table(table(x)))也可以不使用unlist()(也可以使用)。数据和代码在这里:http://emilkirkegaard.dk/en/?p=4928 - CoderGuy123
1
因为您已经加载了Hmisc包,该包会加载一个单独的hist.data.frame S3方法;它会以与基本R中的hist.default不同的方式选择要使用的箱数。 (这已经到了应该作为新问题提出的地步。) - Ben Bolker
嗯,我大部分时间都使用Hmisc,这就解释了为什么我总是不得不使用unlist()。 :) - CoderGuy123
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接