2013-02-02 30 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)