具有非对称成本函数的线性回归?

数据挖掘 机器学习 逻辑回归
2021-09-30 00:16:14

我想预测一些价值 Y(x) 我试图得到一些预测 Y^(x) 在尽可能低但仍大于 Y(x). 换句话说:

cost{Y(x)Y^(x)}>>cost{Y^(x)Y(x)}

我认为一个简单的线性回归应该做得很好。所以我有点知道如何手动实现这个,但我想我不是第一个遇到这种问题的人。是否有任何软件包/库(最好是 python)在做我想做的事情?我需要查找的关键字是什么?

如果我知道一个函数Y0(x)>0其中Y(x)>Y0(x)实施这些限制的最佳方式是什么?

3个回答

如果我对您的理解正确,那么您想在高估方面犯错。如果是这样,您需要一个适当的非对称成本函数。一个简单的候选方法是调整平方损失:

L:(x,α)x2(sgnx+α)2

其中1<α<1是一个参数,您可以使用它来权衡低估与高估的惩罚。α的正值α会惩罚高估,因此您需要将α设置为负值。在 python 中,这看起来像def loss(x, a): return x**2 * (numpy.sign(x) + a)**2

a 的两个值的损失函数

接下来让我们生成一些数据:

import numpy
x = numpy.arange(-10, 10, 0.1)
y = -0.1*x**2 + x + numpy.sin(x) + 0.1*numpy.random.randn(len(x))

任意功能

最后,我们将在tensorflowGoogle 的机器学习库 中进行回归,该库支持自动微分(使此类问题的基于梯度的优化更简单)。我将使用这个示例作为起点。

import tensorflow as tf

X = tf.placeholder("float") # create symbolic variables
Y = tf.placeholder("float") 

w = tf.Variable(0.0, name="coeff")
b = tf.Variable(0.0, name="offset")
y_model = tf.mul(X, w) + b

cost = tf.pow(y_model-Y, 2) # use sqr error for cost function
def acost(a): return tf.pow(y_model-Y, 2) * tf.pow(tf.sign(y_model-Y) + a, 2)

train_op = tf.train.AdamOptimizer().minimize(cost)
train_op2 = tf.train.AdamOptimizer().minimize(acost(-0.5))

sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)

for i in range(100):
    for (xi, yi) in zip(x, y): 
#         sess.run(train_op, feed_dict={X: xi, Y: yi})
        sess.run(train_op2, feed_dict={X: xi, Y: yi})

print(sess.run(w), sess.run(b))

cost是正则平方误差,而acost是前面提到的不对称损失函数。

如果你使用cost你会得到

1.00764 -3.32445

成本

如果你使用acost你会得到

1.02604 -1.07742

成本

acost显然尽量不要低估。我没有检查收敛,但你明白了。

@Emre 的解决方案非常有趣。因此,我尝试使用@Emre 提出的成本函数并从头开始编写代码以拟合线性回归。对于那些不想使用 Tensorflow 的人来说,它可能很有用。这是我的代码:

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import make_regression


# generate regression dataset
X, y = make_regression(n_samples=100, n_features=1, noise=30)



def cost_MSE(y_true, y_pred, a = 0):
    '''
    Cost function
    '''
    # Shape of the dataset
    n = y_true.shape[0]
    
    # Error 
    error = y_true - y_pred
    
    # Compute the sign part of the loss function
    signs = np.sign(error) + a
    
    # Cost
    mse = np.dot(np.multiply(error, error), np.multiply(signs, signs)) / n
    return mse


def cost_derivative(X, y_true, y_pred, a = 0):
    '''
    Compute the derivative of the loss function
    '''
    # Shape of the dataset
    n = y_true.shape[0]
    
    # Error 
    error = y_true - y_pred
    
    # Compute the sign part of the loss function
    signs = np.sign(error) + a
    
    # Compute the sign part of the loss function
    signs = np.multiply(signs, signs)
    
    # Derivative
    der = -2 / n * np.dot(np.multiply(X, error), signs)

    return der


# Lets run an example

X_new = np.concatenate((np.ones(X.shape), X), axis = 1)
learning_rate = 0.1
X_new_T = X_new.T
n_iters = 20
# this variable is used to adjust the degree of underestimation or overestimation
# please take a look at the attached figure for more clarification. 
# if a = 0 >>> no underestimation or overestimation
a = 0
mse = []

#initialize the weight vector
alpha = np.array([0, np.random.rand()])

for _ in range(n_iters):
    
    # Compute the predicted y
    y_pred = np.dot(X_new, alpha)
    
    # Compute the MSE
    mse.append(cost_MSE(y, y_pred, a))
    
    # Compute the derivative
    der = cost_derivative(X_new_T, y, y_pred, a)
    
    # Update the weight
    alpha  -= learning_rate * der

这也是我在不同场景下的结果。

在此处输入图像描述

如果您有任何意见,请告诉我。我会将您的评论应用于代码并更新答案。

选择一个不对称的损失函数。一种选择是分位数回归(线性但正负误差的斜率不同)。