2013-02-21 79 views
2

我有一個正數值的向量。我需要對它進行歸一化,以使得這些值的總和爲1(例如概率)。這很簡單,只需使用x_i/sum(x)作爲權重。但這裏需要注意的是:我需要沒有重量會低於某個最小截止點,而不是重量要大於某個最大截止點。現在,這意味着兩件事:首先,這意味着有些案例沒有解決方案(例如,如果最大截止值爲0.2,則3個對象不能是權重)。其次,這意味着權重的「相對性」被打破。也就是說,在標準歸一化中(其中w_i是給所有i的x_i的權重),對於所有i,j,w_i/w_j = x_i/x_j。與截止時間,這是不能做到的。 更正式我想找到一個函數w = rwc(x,min,max),其中x是一個向量,返回一個具有以下屬性的相同長度的向量:相對權重與截止

1)sum(w )= 1

2)分鐘< = w_i < = MAX對所有的i

3)如果X_I < = x_j然後w_i如果< =對所有w_j I,J

4)w_i和w_j與截斷值(最小值和最大值)都不相同,則它們保持相關性:也就是說,如果min < w_i < max和min < w_j < max然後w_i/w_j = x_i/x_j

如果沒有解決方案應該返回NULL。

所以我的問題是:

一)你如何建議這樣做(在讀或任何其他語言)?

b)中給定的x,可以有一個以上的溶液(即,至少兩個不同的載體,W和V中,每個符合上述的正式要求)

這不是嚴格的R的問題,但我在一個我在R做的項目中遇到了它,所以我將它作爲R.發佈,歡迎任何關於更好分類的建議。

更新

按照下面和經過思考討論,似乎有必要到第五需求增加上述4: 5)滿足1-4權重的所有可能的分配,W是最小權重(最小或最大)數量最少的那個。

這裏是我的[R代碼(希望)做的是:

# 
mwc = function(x,mxw=1,mnw=0) { 
cake = 1 
agnts = 1:length(x) 
result = numeric(length(x)) 
while(cake>0 & length(agnts)>0) { 
    tmp = cake*x[agnts]/sum(x[agnts]) 
    low = which(tmp<mnw) 
    high = which(tmp>mxw) 
    if(length(low)+length(high)==0) { 
     result[agnts] = tmp[agnts] 
     break; 
    } 
    if (length(low)>0) { 
     result[agnts[low]] = mnw 
    } 
    if (length(high)>0) { 
     result[agnts[high]] = mxw 
    } 
    cake = 1-sum(result) 
    agnts=agnts[-c(low,high)] 
} 
if (cake<0) return(NULL) #no solution 
if (abs(sum(result)-1)>1e-17) return(NULL) 
return(result) 
} 
# the end 
+0

您的代碼過於貪婪。一個微不足道的反例:min是0.05,max是0.8; v是[1,1,1000000]。如果我正確理解了你的代碼,它將會失敗,因爲第一步將把最小/最大值分配給w中的所有元素,剩餘部分放在'cake'中。但是,[.1,.1,.8]是一個有效的解決方案。還有其他的情況下,算法會產生一個非最小的解決方案,根據您的標準5. – rici 2013-02-21 22:13:45

+0

好的。真正。有什麼建議麼? – amit 2013-02-22 20:24:22

回答

1

一)

我建議蠻力迭代算法。

  1. x' = x
  2. 計算sum(x')
  3. 計算截止極限min_xmax_x
  4. 計算x'x,調整所有的值的範圍外[min_xmax_x]
  5. 重複2-4直到x'穩定
  6. 計算w

在大多數情況下,迭代次數應該很少。 b)如果存在min或max(但不是兩者),則解矢量是唯一的。

如果同時存在min和max,我不確定。感覺它應該是獨一無二的,但我找不到一個簡單的證明。

+0

爲什麼獨一無二?它對我來說並不明顯。 – amit 2013-02-21 13:17:43

+0

你說得對。起初,我只考慮最大。我爲a)和b)編輯了我的答案。 – 2013-02-21 14:21:26

+0

好的。多想了一下。這當然不是獨一無二的。考慮10個彼此非常接近的數字,min = 0.05,max = 0.15。那麼顯而易見的權重將是根據它們的實際值給所有數字權重非常接近0.1。或者你可以取最小和最大的數字,並分別將它們的權重設置爲0.05和0.15,然後將其他8個數字的權重設置爲非常接近0.1,並且它仍然滿足條件。所以解決方案不是唯一的。我想我可以添加要求最低限度使用截止值的要求。 – amit 2013-02-21 15:03:45

0

你的意思是這樣嗎?這個例子在Haskell中,「[]」表示一個空的列表。

weights :: [Double] -> Double -> Double -> [Double] 
weights my_vector min max = 
    let s = sum my_vector 
     try = map (/s) my_vector 
    in if all (>=min) try && all (<=max) try 
     then try 
     else [] 

OUTPUT:
*主要>權重[1,2,3,4] 0 2
[0.1,0.2,0.3,0.4]
*主要>權重[1,2,3, 4] 1 2
[]

UPDATE:
這裏的一個粗略的方向(Haskell中再次),基於this

import Data.List 
import Data.Ord 

normalize :: Double -> Double -> Double -> Double -> Double 
normalize targetMin targetMax rawMax val = 
    let maxReduce = 1 - targetMax/rawMax 
     factor = maxReduce * (abs val)/rawMax 
    in max ((1 - factor) * val) targetMin 

weights :: [Double] -> Double -> Double -> [Double] 
weights myVector targetMin targetMax = 
    let try = map (/(sum myVector)) myVector 
    in if all (>=targetMin) try && all (<=targetMax) try 
     then try 
     else weights normalized targetMin targetMax 
    where normalized = 
      let targetMax' = (maximum myVector * targetMin/minimum myVector) 
      in map (\x -> normalize targetMin targetMax' (maximum myVector) x) myVector 

OUTPUT:
*主要>權重[4,4,4,1000] 0.1 0.7
[0.10782286784365082,0.10782286784365082,0.10782286784365082,0.6765313964690475]
*主要>權重[1,1,1000000] 0.05 0.8
[0.1204381​​8322274577,0.1204381​​8322274577,0.7591236335545084]

+0

沒有。那太簡單了。雖然你的例子是正確的,但代碼當然不會試圖找到任何調整,這將導致非零解決方案 – amit 2013-02-21 13:28:26

+0

@amit ...我很困惑。你能給出一個簡單的例子,其中x的調整使他們滿足你的條件,但是不滿足所有i,j的w_i/w_j = x_i/x_j? – 2013-02-21 14:23:50

+0

例如x = [4,4,4,1000],最大截止值爲0.7,最小截止值爲0,那麼權重[0.1,0.1,0.1,0.7]滿足所有條件,但當然,第四個數字應該更高,所以它與其他權重的關係被打破。 – amit 2013-02-21 14:59:50

0

這是現在,我希望我的第二個答案,地址要求4)爲好。在我看來,如果要求4)是應用那麼我們必須把那些沒有被指定爲臨界值的所有元素:

denominator = sum non_cutoff_elements/(1 - sum cutoff_elements) 

哪裏cutoff_elements'被表達爲他們的臨界值。我希望,這個遞歸代碼試圖耗盡截止分配的組合。代碼似乎在他們的評論中解決了amit和rici的例子。 Haskell中再次:

import Data.List 
import Data.Ord 

weights :: [Double] -> Double -> Double -> [[Double]] 
weights myVector tMin tMax = 
    weights' 0 
    where 
     weights' count 
     | count == length myVector + 1 = [] 
     | otherwise = 
      let new_list = take count myVector 
          ++ replicate (length myVector - count) tMax 
      in fromLeft new_list 0 ++ weights' (count+1) 
       where 
        fromLeft list' count' = 
        let non_cutoffs = filter (\x -> x/=tMin && x/=tMax) list' 
         real_count = length list' - length non_cutoffs 
         cutoffs_l = filter (\x -> x==tMin) list' 
         cutoffs_r = filter (\x -> x==tMax) list' 
         denom = sum non_cutoffs/(1 - (sum $ cutoffs_l ++ cutoffs_r)) 
         mapped = cutoffs_l ++ (map (/denom) non_cutoffs) ++ cutoffs_r 
         next_list = let left = tMin : cutoffs_l 
             right = drop 1 cutoffs_r 
            in left ++ non_cutoffs ++ right 
        in if count' == real_count 
          then [] 
          else if sum cutoffs_r > 1 || sum cutoffs_l > 1 
            || sum cutoffs_r + sum cutoffs_l > 1 
            then fromLeft next_list (count'+1) 
          else if sum mapped == 1 && all (>=tMin) mapped && all (<=tMax) mapped 
            then mapped : fromLeft list' (count'+1) 
            else fromLeft next_list (count'+1) 

OUTPUT:
*主要>權重[4,4,4,1000] 0.1 0.7
[[0.1,0.1,0.1,0.7],[0.1,0.1,0.10000000000000009,0.7 ],[0.1,0.10000000000000003,0.10000000000000003,0.7],[0.10000000000000002,0.10000000000000002,0.10000000000000002,0。7]]
小數點後14位:[[0.1,0.1,0.1,0.7],[0.1,0.1,0.1,0.7],[0.1,0.1,0.1,0.7],[0.1,0.1,0.1,0.7 ]

*主要>權重[1,1,1000000] 0.05 0.8
[[5.0E-2,0.1499999999999999,0.8],[9.999999999999998e-2,9.999999999999998e-2,0.8]
四捨五入到小數點後14位:[[0.05,0.15,0.8],[0.1,0.1,0.8]]

+0

哇...我承認我無法遵循代碼到最後,所以我不完全明白你做了什麼。可能是因爲Haskell不是我的特長。 – amit 2013-02-22 21:24:40

+0

@amit ...如果你理解我的頂部的前提(即,對於每個將值分配/轉換爲臨界值的情況,只有一個分母適用於可以滿足條件的剩餘值)嘗試所有截止分配的組合,例如[CU VAL VAL VAl],[CU VAL VAL CU],[CU,CU,VAL,CU]等,然後應用公式中的分母在頂部,看看是否總和等於1並且值在範圍內。就我個人而言,我喜歡更平滑的歸一化逼近,它不遵循規則4(在我的其他答案中......)無論如何,thx很有趣 – 2013-02-22 22:50:44