У меня есть 2 массива по n элементов в каждом. Первый - это процент (от 0% до 100%), при котором сумма всех элементов дает 100%. Второй составлен из целых чисел от -3 до 3 (включительно).
Цель моего сценария состоит в том, чтобы изменять числа ровно настолько, чтобы получить суммарный продукт, равный примерно 0.
Здесь это то, что у меня есть до сих пор, и, похоже, работает:
import numpy as np
import cvxpy as cp
# Emulated user inputs
n = 10
arr1 = np.random.rand(n)
arr1 = arr1/np.sum(arr1)
arr2 = np.random.randint(-3, 3, n)
while not (-0.1 < np.sum(np.dot(arr1, arr2)) < 0.1): # User ensures this condition before running
arr2 = np.random.randint(-3, 3, n)
print("Initial array =", arr2)
print("Initial sum product =", np.sum(np.dot(arr1, arr2)), "\n")
# Gradually increase allowable element-wise delta
for delta_limit in range(2, 7): # Variation of 2 is acceptable for first iteration
# Create variable for new array
arr3 = cp.Variable(len(arr2), integer=True)
# Define constraints
constraints = [-0.000050001 <= arr3 * arr1, # Not working, but it's supposed to target sum product ~0
arr3 * arr1 <= 0.000049999, # Not working, but it's supposed to target sum product ~0
-3 <= arr3, # Lower bound of -3
arr3 <= 3, # Upper bound of +3
-delta_limit <= arr2 - arr3, # Restrict element-wise difference by less than +/-delta_limit
arr2 - arr3 <= delta_limit] # Restrict element-wise difference by less than +/-delta_limit
# Objective function (minimize variation between arr3 and arr2)
objective = cp.Minimize(cp.multiply((1 / (len(arr2) - 1)), cp.sum(cp.power((arr3 - arr2) - arr2.mean(), 2))))
# Solve
solution = cp.Problem(objective, constraints).solve()
# Check if a solution was found
if arr3.value is None and delta_limit < 6:
continue
elif arr3.value is None and delta_limit == 6:
print("No solution found, try another combination")
else:
# Change float to integer
arr3.value = arr3.value.astype(int)
# Print results
print("New array =", arr3.value)
print("New sum product =", np.sum(np.dot(arr1, arr3.value)), "\n")
print("Differences =", arr3.value - arr2)
print("Total difference =", np.round(np.sum(np.absolute(arr3.value - arr2))))
break
Это, например, напечатает следующее:
Initial array = [ 1 1 1 -2 2 2 -2 0 -2 -2]
Initial sum product = -0.05254026276509359
New array = [ 0 0 0 -2 1 1 -2 0 -1 -2]
New sum product = -0.3703945724305102
Differences = [-1 -1 -1 0 -1 -1 0 0 1 0]
Total difference = 6
Однако я хотел бы добавить еще 1 ограничение : «знак элементов в первом массиве должен быть сохранен в новом массиве». Я бы предпочел сделать это как ограничение, а не только для проверки l oop.
Я пробовал такие вещи безуспешно:
a) np.sign(arr2) == np.sign(arr3)
b) np.sign(arr2) == cp.multiply(arr3 + 0.1, cp.power(cp.power(arr3 + 0.1, 2, -0.5))
И многое другое, я просто могу не взломать ... :( Кроме того, если у вас есть предложения по улучшению, я очень открыт для них.
Заранее спасибо!