2013-02-02 35 views
0

给定具有x * y个单元格的网格(或表格)。每个单元格都包含一个值。大多数这些单元格的值都是0,但在此网格的某个位置可能存在一个“热点”,而该单元格的值很高。该单元的邻居也具有大于0的值。随着距离热点越远,相应网格单元中的值越低。如何计算网格中的重心?

所以这个热点可以被看作是山顶,随着价值越来越低,我们远离这座山丘。在一定距离处,值再次下降到0。

现在我需要确定网格中代表网格重心的单元格。在上面这个简单的例子中,这个矩心只是一个最高值的单元。然而,它并不总是那么简单:

  1. 围绕热点小区相邻小区的减少值可能不会平均分配,或者“山边”可能会掉下来,以0比另一侧更快。

  2. 在网格内还有另一个热点/山丘,值> 0的其他地方。

我可以认为这是一种典型的问题。不幸的是,我不是数学专家,所以我不知道要搜索什么(至少我没有在Google中找到答案)。

任何想法如何解决这个问题?

在此先感谢。

+0

您的网格是2D平面吗? – eLRuLL

+0

我不确定你的意思是“2D飞机”,但我认为是。它基本上是一个浮点值的二维数组。 – Matthias

+0

正如你所说,这是一个数学问题,也许你应该在http://math.stackexchange.com/上发布它。 – eLRuLL

回答

3

您正在寻找单元格值的“加权平均值”。假设每个单元都有一个值Z(X,Y),那么你可以做以下

zx = sum(z(x, y)) over all values of y 
zy = sum(z(x, y)) over all values of x 

meanX = sum(x * zx(x))/sum (zx(x)) 
meanY = sum(y * zy(y))/sum (zy(y)) 

我相信你可以转换成您所选择的语言这...

例子:如果你知道MATLAB,那么上述将被写入如下

zx = sum(Z, 1); % sum all the rows 
zy = sum(Z, 2); % sum all the columns 

[ny nx] = size(Z); % find out the dimensions of Z 

meanX = sum((1:nx).*zx)/sum(zx); 
meanY = sum((1:ny).*zy)/sum(zy); 

这将使你的meanX范围为1 .. NX:如果它的正中间,该值将是(NX + 1)/ 2。你显然可以根据你的需要来扩展它。

编辑:一次,在 “几乎实时” 代码:

// array Z(N, M) contains values on an evenly spaced grid 
// assume base 1 arrays 

zx = zeros(N); 
zy = zeros(M); 

// create X profile: 
for jj = 1 to M 
    for ii = 1 to N 
    zx(jj) = zx(jj) + Z(ii, jj); 
    next ii 
next jj 

// create Y profile: 
for ii = 1 to N 
    for jj = 1 to M 
    zy(ii) = zy(ii) + Z(ii, jj); 
    next jj 
next ii 

xsum = 0; 
zxsum = 0; 
for ii = 1 to N 
    zxsum += zx(ii); 
    xsum += ii * zx(ii); 
next ii 
xmean = xsum/zxsum; 

ysum = 0; 
zysum = 0; 
for jj = 1 to M 
    zysum += zy(jj); 
    ysum += jj * zy(ii); 
next jj 
ymean = ysum/zysum; 
+0

谢谢,我认为这会让我走向正确的方向。虽然我不是很了解Matlab,所以我还没有完全理解你的解决方案。你会如此善良,向我解释,也许是伪代码? – Matthias

+0

第一个块是伪代码 – eLRuLL

1

This Wikipedia entry可以帮助;标题为“粒子系统”的部分就是您所需要的。只要理解你需要为每个维度进行一次计算,其中显然有两个维度。

这里是一个完整的Scala 2.10程序来生成网格完全随机整数(使用命令行上指定的尺寸),并找到重心(其中行和列被编号为从1开始):

object Ctr extends App { 
    val Array(nRows, nCols) = args map (_.toInt) 
    val grid = Array.fill(nRows, nCols)(util.Random.nextInt(10)) 
    grid foreach (row => println(row mkString ",")) 
    val sum = grid.map(_.sum).sum 
    val xCtr = ((for (i <- 0 until nRows; j <- 0 until nCols) 
    yield (j+1) * grid(i)(j)).sum :Float)/sum 
    val yCtr = ((for (i <- 0 until nRows; j <- 0 until nCols) 
    yield (i+1) * grid(i)(j)).sum :Float)/sum 
    println(s"Center is ($xCtr, $yCtr)") 
} 

你可以定义一个函数来保持计算DRYer,但我想尽可能保持它的显着性。无论如何,在这里我们运行它几次:

$ scala Ctr 3 3 
4,1,9 
3,5,1 
9,5,0 
Center is (1.8378378, 2.0) 

$ scala Ctr 6 9 
5,1,1,0,0,4,5,4,6 
9,1,0,7,2,7,5,6,7 
1,2,6,6,1,8,2,4,6 
1,3,9,8,2,9,3,6,7 
0,7,1,7,6,6,2,6,1 
3,9,6,4,3,2,5,7,1 
Center is (5.2956524, 3.626087)