限制列表中的数字并重新分配列表中的多余数字

时间:2019-07-17 12:33:14

标签: python finance

我正在尝试使用Python编写一个函数,以在输入列表时找到一个最大值,该函数将限制列表中的值,并将从数字中减去的多余部分按比例重新分配给列表中的其他数字。

例如,我希望[0.05,0.02,0.05,0.08,0.80]通过最大为0.3的函数成为[0.175,0.07,0.175,0.28,0.30]。

目前,我在Python中有类似的内容:

'''

import numpy as np

x = np.array([0.05, 0.05, 0.02, 0.08, 0.80])
limit = 0.3


excess = 0
y = np.zeros(len(x))
z = np.zeros(len(x))

for i in range(len(x)):
    if x[i] > limit:
        excess = x[i] - limit
        x[i] = 0
        y[i] = limit
        z = x*(1/sum(x)*excess)
        z = z+x+y

'''

z是此特定数组的结果。

'''

z = array([0.175, 0.175, 0.07 , 0.28 , 0.3  ])

'''

但是,当我有多个超出限制的数字,或者数组的顺序不同时,这种情况就会消失。

1 个答案:

答案 0 :(得分:0)

您可以使用以下脚本实现目标。这个想法是采用“多余的重量”,并在体重不足的元素上重复地分配它,直到所有元素都被覆盖。需要重新进行此过程,因为重新分配可能会使某些原本偏低的要素超出上限。另外,您没有明确提及它,但是基于财务标签和您的示例,我假设列表的总和需要保持不变。

首先,我创建了一个熊猫数据框,其中包含20个总计为1的值,并按降序对其进行排序。

    Elements    Uncon
3   D   0.081778
1   B   0.079887
19  T   0.079451
17  R   0.070283
11  L   0.068052
4   E   0.057335
12  M   0.054695
5   F   0.051099
6   G   0.049873
18  S   0.049469
14  O   0.045059
16  Q   0.043583
8   I   0.041186
2   C   0.036802
7   H   0.036315
13  N   0.035440
0   A   0.034311
15  P   0.031519
10  K   0.027173
9   J   0.026689

第二,我们将上限设置为0.06。对于您面临的多个超重元素问题,这将成为一个很好的测试案例。

cap = 0.06
weights = df.Uncon

下面是迭代脚本。

# Obtain constrained weights
constrained_wts = np.minimum(cap, weights)
# Locate all stocks with less than max weight
nonmax = constrained_wts.ne(cap)
# Calculate adjustment factor - this is proportional to original weights
adj = ((1 - constrained_wts.sum()) *
        weights.loc[nonmax] / weights.loc[nonmax].sum())
# Apply adjustment to obtain final weights
constrained_wts = constrained_wts.mask(nonmax, weights + adj)
# Repeat process in loop till conditions are satisfied
while ((constrained_wts.sum() < 1) or
       (len(constrained_wts[constrained_wts > cap]) >=1 )):
    # Obtain constrained weights
    constrained_wts = np.minimum(cap, constrained_wts)
    # Locate all stocks with less than max weight
    nonmax = constrained_wts.ne(cap)
    # Calculate adjustment factor - this is proportional to original weights
    adj = ((1 - constrained_wts.sum()) *
        constrained_wts.loc[nonmax] / weights.loc[nonmax].sum())
    # Apply adjustment to obtain final weights
    constrained_wts = constrained_wts.mask(nonmax, constrained_wts + adj)

然后可以将结果重新分配给数据框并进行比较。

df['Cons'] = constrained_wts
 Elements Uncon       Cons
0   A   0.034311    0.039189
1   B   0.079887    0.060000
2   C   0.036802    0.042034
3   D   0.081778    0.060000
4   E   0.057335    0.060000
5   F   0.051099    0.058364
6   G   0.049873    0.056964
7   H   0.036315    0.041478
8   I   0.041186    0.047041
9   J   0.026689    0.030483
10  K   0.027173    0.031037
11  L   0.068052    0.060000
12  M   0.054695    0.060000
13  N   0.035440    0.040479
14  O   0.045059    0.051465
15  P   0.031519    0.036001
16  Q   0.043583    0.049780
17  R   0.070283    0.060000
18  S   0.049469    0.056502
19  T   0.079451    0.060000

元素M是说明为什么需要重复过程的一个很好的例子。它最初是轻量级的,但是非常接近上限,以至于在第一次重新分配后它会变得超重。