在Python中,假设我有连续变量x
和y
,其值在0和1之间是有界的(更容易)。我的假设一直是,如果我想这些变量转换成序数值与箱会像0,0.01,0.02,...,0.98,0.99,1一个可以简单地圆的原始值到第二位。出于某种原因,当我这样做,它留下的文物。
让我来说明问题(但通知我的问题不是如何才能得到正确的情节,但实际上如何这样做二进制化右)。首先这些都是一个需要重现该问题的唯一模块:
import numpy as np
import matplotlib.pyplot as plt
现在,假设我们有一个如下(其他数据产生过程也将给予同样的问题)产生连续的数据有:
# number of points drawn from Gaussian dists.:
n = 100000
x = np.random.normal(0, 2, n)
y = np.random.normal(4, 5, n)
# normalizing x and y to bound them between 0 and 1
# (it's way easier to illustrate the problem this way)
x = (x - min(x))/(max(x) - min(x))
y = (y - min(y))/(max(y) - min(y))
那么,让我们转换只是通过应用一些四舍五入x
和y
在上述区间序号。然后,我们将结果存入由x
矩阵y
为了画出它的热图,用于说明目的:
# matrix that will represent the bins. Notice that the
# desired bins are every 0.01, from 0 to 1, so 100 bins:
mtx = np.zeros([100,100])
for i in range(n):
# my idea was that I could roughly get the bins by
# simply rounding to the 2nd decimal point:
posX = round(x[i], 2)
posY = round(y[i], 2)
mtx[int(posX*100)-1, int(posY*100)-1] += 1
我希望的工作上面,但是当我绘制矩阵mtx
的内容,其实我得到奇怪的文物。编码:
# notice, however, the weird close-to-empty lines at
# 0.30 and 0.59 of both x and y. This happens regardless
# of how I generate x and y. Regardless of distributions
# or of number of points (even if it obviously becomes
# impossible to see if there are too few points):
plt.matshow(mtx, cmap=plt.cm.jet)
plt.show(block=False)
给我:
最奇怪的是,无论我使用的分布产生x
和y
或种子我使用的RNG,我总是得到相同的水平和垂直近空行,在0.30和两个x
和y
0.59,经常与行立即平行于点的那些表示浓度(如你在图像中看到)。
当我按值从矩阵到控制台打印值,其实我可以确认,对应于这些近空行的那些确实为零或非常接近零 - 不同于他们的邻居点。
我的问题可以更恰当地分为2个:
x
矩阵,根据切点0,0.01,0.02,垃圾桶的值y
...,0.98,0.99,1不留上面的文物?如果一个人想容易抓住直接在一块上面使用的整个例子的代码,这里是链接:https://www.codepile.net/pile/VLAq4kLp
注:我不希望找到绘制的正确途径。我想找到myeself生成表示是上述情节的“分级值矩阵”的正确途径。我知道有其他的方法来完成热图无文物绘制,例如使用plt.matshow(mtx, cmap=plt.cm.jet); plt.show(block=False)
或plt.hist2d(x, y, bins=100)
。我所问的是哪里是我的矩阵生成本身,它可以生成接近零元素的问题。
这个问题可以用np.histogram2d(x,y, bins=100)
迎刃而解。
在这个答案的其余部分是展示,其中,人工算法失败:
考虑到数字
0.56*100 == 56.00000000000001 -> int(0.56*100) == 56
0.57*100 == 56.99999999999999 -> int(0.57*100) == 56
0.58*100 == 57.99999999999999 -> int(0.58*100) == 57
0.59*100 == 59.00000000000000 -> int(0.59*100) == 59
使得58号根本不会发生在你的索引,而56号将出现两次作为经常(为均匀分布)。
您可以改为先乘,然后截断为整数。还要注意的是最后一个块需要被关闭,使得1的值被添加到bin与指数99。
mtx = np.zeros([100,100])
for i in range(n):
posX = int(x[i]*100)
posY = int(y[i]*100)
if posX == 100:
posX = 99
if posY == 100:
posY = 99
mtx[posX, posY] += 1
这将经由所述边缘限定的箱柜,即第一箱范围从0到1等。在调用imshow / matshow你会然后需要通过设置在何种程度上考虑到这一点。
plt.matshow(mtx, cmap=plt.cm.jet, extent=(0,100,0,100))
你有你的方法的问题是一个浮点错误。当你尝试把你的圆角数为整数这将很明显。考虑下面的函数(这是你正在做您的每一个随机数的本质是什么):
def int_round(a):
r = round(a, 2)
rh = r*100
i = int(rh)
print(r, rh, i)
int_round(0.27)
#prints: 0.27 27.0 27
int_round(0.28)
#prints: 0.28 28.000000000000004 28
int_round(0.29)
#prints: 0.29 28.999999999999996 28
int_round(0.30)
#prints: 0.3 30.0 30
正如你可以四舍五入0.28和0.29和100都0.28
相乘,之后看到的,因为浮点错误,并0.29
结束了28
的整数。 (这是因为int()
始终几轮下来,所以28.99999999999变成28)。
溶液可以是乘以100后四舍五入的值:
def round_int(a):
ah = a*100
rh = round(ah, 2)
i = int(rh)
print(ah, rh, i)
round_int(0.27)
#prints: 27.0 27.0 27
round_int(0.28)
#prints: 28.000000000000004 28.0 28
round_int(0.29)
#prints: 28.999999999999996 29.0 29
round_int(0.30)
#prints: 30.0 30.0 30
请注意,在这种情况下0.29
校正转换为29
。
运用这一逻辑代码:我们可以通过改变for
环路:
mtx = np.zeros([101, 101])
for i in range(n):
# my idea was that I could roughly get the bins by
# simply rounding to the 2nd decimal point:
posX = np.round(100*x[i], 2)
posY = np.round(100*y[i], 2)
mtx[int(posX), int(posY)] += 1
注意仓的数量增加至101以考虑到最终仓当x = 1或y = 1。此外,在这里你可以看到,由于我们之前四舍五入乘以x[i]
和y[i]
100,装仓正确发生:
我不知道如何准确地回答你的第一个问题。但对于分档项目我也使用pandas.cut。为了您的解决方案,你可以做
import pandas as pd
bins = [v / 100. for v in range(100)
bucketed = pd.cut(x, bins)
然后bucketed
将指示每个数据点属于哪个区间
仅供参考这里就可以了http://benalexkeen.com/bucketing-continuous-variables-in-pandas/一个体面的教程
截至目前,我只能回答你的第二个问题正确,因为我仍然在寻找在第一部分中的错误。
因此,这里是你会选择像你想宾尼标准溶液(假设x
和y
你前面提到的):
h = plt.hist2d(x, y, bins=100)
给
这是一个100×100的网格。
变量h
现在包含你想要的矩阵,也matplotlib发现垃圾箱。 plt.matshow(h[0])
示出了如在图中看到,这是由matplotlib返回的相同矩阵。正如在评论中提到:你可以得到相同的结果(但没有自动情节)通过调用
h = np.histogram2d(x, y, bins=100)
尽管如此,你的算法是不对的,因为你实际上是指望边缘项目的数量,而不是它们之间,所以你在每个方向101项。你可以看到这个问题,posX==0
例如当:然后int(posX*100)-1
产生-1
。