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) 总和(w)=1

2) min <= w_i <= max for all 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。

所以我的问题是:

a) 你如何建议这样做(用 R 或任何其他语言)?

b) 给定 x,是否有多个解(即至少有两个不同的向量 w 和 v,每个都符合上述形式要求)

这不是严格意义上的 R 问题,但我在 R 中做的一个项目中遇到了它,所以我将它作为 R 发布。欢迎任何关于更好分类的建议。

更新

在下面的讨论和更多的思考之后,似乎有必要在上面的 4 中添加第五个要求:5)在满足 1-4 的所有可能的权重分配中,W 是具有最小数量的极端权重(最小或最大)。

这是(希望)这样做的 my 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
4

3 回答 3

1

一个)

我建议使用蛮力迭代算法。

  1. x' = x
  2. 计算sum(x')
  3. 计算临界值min_xmax_x
  4. x'从计算x,调整范围之外的所有值 [ min_x, max_x]
  5. 重复2-4直到x'稳定
  6. 计算w

在大多数情况下,迭代次数应该很少。

b)如果存在最小值或最大值(但不是两者),则解向量是唯一的。

如果同时有最小值和最大值,我不确定。感觉它应该是独一无二的,但我找不到简单的证明。

于 2013-02-21T13:09:15.663 回答
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 []

输出:
*Main> 权重 [1,2,3,4] 0 2
[0.1,0.2,0.3,0.4]
*Main> 权重 [1,2,3,4] 1 2
[]

更新:
这是一个粗略的方向(再次是 Haskell),基于

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:
*Main> weights [4,4,4,1000] 0.1 0.7
[0.10782286784365082,0.10782286784365082,0.10782286784365082,0.6765313964690475]
*Main> weights [1,1,1000000] 0.05 0.8
[0.1204381​​8322274577,0.1204381​​8322274577,0.7591236335545084]

于 2013-02-21T13:12:44.570 回答
0

这是我的第二个答案,我希望现在也能解决要求 4)。在我看来,如果要应用要求 4),那么我们必须将所有未指定为截止值的元素除以:

    denominator = sum non_cutoff_elements / (1 - sum cutoff_elements)

其中“cutoff_elements”表示为它们的截止值。我希望,这个递归代码试图用尽截止分配的组合。该代码似乎解决了 amit 和 rici 在其评论中的示例。再次哈斯克尔:

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)

输出:
*主要>重量[4,4,4,4,1000] 0.1 0.7
[[[0.1,0.1,0.1,0.7],[0.1,0.1,0.1000000000000000009,0.7] ,0.100000000000000002,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]]

*Main> weights [1,1,1000000] 0.05 0.8
[[5.0e-2,0.1499999999999999,0.8],[9.9999999999999998e-2,9.999999999999998e-2,0.8]] 舍入
到小数点后 14 位: [[0.05,0.15,0.8],[0.1,0.1,0.8]]

于 2013-02-22T06:14:17.330 回答