Python: 优化投资组合中的权重
Python: Optimize weights in portfolio
我有以下带权重的数据框:
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]})
然后我使用以下方法规范化每一行:
df = df.div(df.sum(axis=1), axis=0)
我想优化每行的归一化权重,使权重不小于 0 或大于 0.4。
如果权重大于 0.4,它将被裁剪为 0.4,额外的权重将按比例分配给其他条目(意味着第二大权重将获得更多权重,因此它接近到0.4,如果还有剩余权重,再分配给第三个,以此类推)。
这可以使用“优化”功能来完成吗?
谢谢。
更新:我还想为权重设置一个最小界限。在我原来的问题中,最小权重界限被自动视为零,但是,我想设置一个约束,例如最小权重至少等于 0.05。
不幸的是,我只能找到一个循环解决这个问题。当您 trim 减去多余的重量并按比例重新分配时,减重可能会超过限制。然后他们必须 trim 治疗。并且循环不断重复,直到没有价值超重。重量不足的行也是如此。
# 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],
}
)
def ensure_min_weight(row: np.array, min_weight: float):
while True:
underweight = row < min_weight
if not underweight.any():
break
missing_weight = min_weight * underweight.sum() - row[underweight].sum()
row[~underweight] -= missing_weight / row[~underweight].sum() * row[~underweight]
row[underweight] = min_weight
def ensure_max_weight(row: np.array, max_weight: float):
while True:
overweight = row > max_weight
if not overweight.any():
break
excess_weight = row[overweight].sum() - (max_weight * overweight.sum())
row[~overweight] += excess_weight / row[~overweight].sum() * row[~overweight]
row[overweight] = max_weight
values = df.to_numpy()
normalized = values / values.sum(axis=1)[:, None]
min_weight = 0.15 # just for fun
max_weight = 0.4
for i in range(len(values)):
row = normalized[i]
ensure_min_weight(row, min_weight)
ensure_max_weight(row, max_weight)
# Normalized weight
assert np.isclose(normalized.sum(axis=1), 1).all(), "Normalized weight must sum up to 1"
assert ((min_weight <= normalized) & (normalized <= max_weight)).all(), f"Normalized weight must be between {min_weight} and {max_weight}"
print(pd.DataFrame(normalized, columns=df.columns))
# Raw values
# values = normalized * values.sum(axis=1)[:, None]
# print(pd.DataFrame(values, columns=df.columns))
请注意,如果您的 min_weight
和 max_weight
不合逻辑,此算法将 运行 进入无限循环:尝试 min_weight = 0.4
和 max_weight = 0.5
。您应该在 2 个 ensure
函数中处理这些错误。
我有以下带权重的数据框:
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]})
然后我使用以下方法规范化每一行:
df = df.div(df.sum(axis=1), axis=0)
我想优化每行的归一化权重,使权重不小于 0 或大于 0.4。
如果权重大于 0.4,它将被裁剪为 0.4,额外的权重将按比例分配给其他条目(意味着第二大权重将获得更多权重,因此它接近到0.4,如果还有剩余权重,再分配给第三个,以此类推)。
这可以使用“优化”功能来完成吗?
谢谢。
更新:我还想为权重设置一个最小界限。在我原来的问题中,最小权重界限被自动视为零,但是,我想设置一个约束,例如最小权重至少等于 0.05。
不幸的是,我只能找到一个循环解决这个问题。当您 trim 减去多余的重量并按比例重新分配时,减重可能会超过限制。然后他们必须 trim 治疗。并且循环不断重复,直到没有价值超重。重量不足的行也是如此。
# 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],
}
)
def ensure_min_weight(row: np.array, min_weight: float):
while True:
underweight = row < min_weight
if not underweight.any():
break
missing_weight = min_weight * underweight.sum() - row[underweight].sum()
row[~underweight] -= missing_weight / row[~underweight].sum() * row[~underweight]
row[underweight] = min_weight
def ensure_max_weight(row: np.array, max_weight: float):
while True:
overweight = row > max_weight
if not overweight.any():
break
excess_weight = row[overweight].sum() - (max_weight * overweight.sum())
row[~overweight] += excess_weight / row[~overweight].sum() * row[~overweight]
row[overweight] = max_weight
values = df.to_numpy()
normalized = values / values.sum(axis=1)[:, None]
min_weight = 0.15 # just for fun
max_weight = 0.4
for i in range(len(values)):
row = normalized[i]
ensure_min_weight(row, min_weight)
ensure_max_weight(row, max_weight)
# Normalized weight
assert np.isclose(normalized.sum(axis=1), 1).all(), "Normalized weight must sum up to 1"
assert ((min_weight <= normalized) & (normalized <= max_weight)).all(), f"Normalized weight must be between {min_weight} and {max_weight}"
print(pd.DataFrame(normalized, columns=df.columns))
# Raw values
# values = normalized * values.sum(axis=1)[:, None]
# print(pd.DataFrame(values, columns=df.columns))
请注意,如果您的 min_weight
和 max_weight
不合逻辑,此算法将 运行 进入无限循环:尝试 min_weight = 0.4
和 max_weight = 0.5
。您应该在 2 个 ensure
函数中处理这些错误。