简体   繁体   English

Python:优化投资组合中的权重

[英]Python: Optimize weights in portfolio

I have the following dataframe with weights:我有以下带有权重的 dataframe:

df = pd.DataFrame({'a': [0.1, 0.5, 0.1, 0.3], 'b': [0.2, 0.4, 0.2, 0.2], 'c': [0.3, 0.2, 0.4, 0.1],
           'd': [0.1, 0.1, 0.1, 0.7], 'e': [0.2, 0.1, 0.3, 0.4], 'f': [0.7, 0.1, 0.1, 0.1]})

and then I normalize each row using:然后我使用以下方法对每一行进行标准化:

df = df.div(df.sum(axis=1), axis=0)

I want to optimize the normalized weights of each row such that no weight is less than 0 or greater than 0.4.我想优化每一行的归一化权重,使得没有权重小于 0 或大于 0.4。

If the weight is greater than 0.4, it will be clipped to 0.4 and the additional weight will be distributed to the other entries in a pro-rata fashion (meaning the second largest weight will receive more weight so it gets close to 0.4, and if there is any remaining weight, it will be distributed to the third and so on).如果权重大于 0.4,它将被剪裁为 0.4,并且额外的权重将按比例分配给其他条目(这意味着第二大权重将获得更多权重,因此接近 0.4,如果有任何剩余重量,它将分配给第三个,依此类推)。

Can this be done using the "optimize" function?这可以使用“优化”function 来完成吗?

Thank you.谢谢你。

Unfortunately, I can only find a loop solution to this problem.不幸的是,我只能找到一个循环解决这个问题。 When you trim off the excess weight and redistribute it proportionally, the underweight may go over the limit.当你剪掉多余的重量并按比例重新分配时,重量不足的重量可能会超过限制。 Then they have to be trimmed off.然后他们必须被修剪掉。 And the cycle keep repeating until no value is overweight.并且循环不断重复,直到没有值超重。

The code below works if all items are greater than 0. Handling items with 0 weight is tricky because you can't shift the excess weight to them (as per your proportional formula).如果所有项目都大于 0,则下面的代码有效。处理重量为 0 的项目很棘手,因为您无法将多余的重量转移给它们(根据您的比例公式)。 You have to define a "seed" weight for them somehow.您必须以某种方式为它们定义“种子”权重。

# The original data frame. No normalization yet
df = pd.DataFrame({
    'a': [0.1, 0.5, 0.1, 0.3],
    'b': [0.2, 0.4, 0.2, 0.2],
    'c': [0.3, 0.2, 0.4, 0.1],
    'd': [0.1, 0.1, 0.1, 0.7],
    'e': [0.2, 0.1, 0.3, 0.4],
    'f': [0.7, 0.1, 0.1, 0.1]}
)

values = df.to_numpy()
normalized = values / values.sum(axis=1)[:, None]
max_weight = 0.4

for i in range(len(values)):
    row = normalized[i]
    while True:
        overweight = row > max_weight
        if not overweight.any():
            break

        # Calculate the excess weight
        excess_weight = row[overweight].sum() - (max_weight * overweight.sum())
        # Distribute this excess weight proportionally to the underweight items
        row[~overweight] += excess_weight / row[~overweight].sum() * row[~overweight]
        # Clip the overweight to max_weight
        row[overweight] = max_weight

    # Floating point math is not exact. We test for "close to 1"
    # as opposed to "exactly equal 1"
    assert np.isclose(row.sum(), 1)
    normalized[i] = row

values = normalized * values.sum(axis=1)[:, None]

Output: Output:

> df
  a   b   c   d   e   f
0.1 0.2 0.3 0.1 0.2 0.7
0.5 0.4 0.2 0.1 0.1 0.1
0.1 0.2 0.4 0.1 0.3 0.1
0.3 0.2 0.1 0.7 0.4 0.1

> pd.DataFrame(values, columns=df.columns)
       a        b    c        d        e    f
0.106667 0.213333 0.32 0.106667 0.213333 0.64
0.500000 0.400000 0.20 0.100000 0.100000 0.10
0.100000 0.200000 0.40 0.100000 0.300000 0.10
0.300000 0.200000 0.10 0.700000 0.400000 0.10

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM