处理回归问题中太多零的最佳方法?

数据挖掘 机器学习 回归 熊猫
2021-10-06 13:30:42

我正在尝试使用 TensorFlow 和 Pandas 解决一个简单的回归问题,以查看给定产品的预期转化率,因为我愿意为每次访问支付多少费用(每次点击成本或cpc)。

每个数据点代表一天及其给定的购置成本和转化率。我预计随着访问量的增加,转化率会成倍下降,因为我的受众越来越广泛,不再那么专注了。

数据似乎同意这一点:

购置成本 X 转化率

问题在于,对于大多数数据点,转换率为(即没有产品售出),因此任何模型都可能仅通过猜测零销售额来表现良好。对于这个特定的子集(最畅销的产品之一),零与非零的比率大约为 4:1,但在一般数据中约为 300:1。

我能想到的两种最好的方法是

a)按足够大的时间段汇总数据以包含至少一次转换(问题是我必须解决平均成本而不是更详细的每日数据而丢失数据)

b) 将问题拆分为分类问题(我会至少销售一个单位)和回归问题(假设我要销售至少一个单位,我可以预期销售多少单位

这两个听起来像一个聪明的主意吗?是否有任何行之有效的方法来解决此类问题?

3个回答

选项 (b) 是一个很好的方法。如果您使用输出概率的分类器,您甚至可以将两个模型输出相乘以计算可解释为联合可能性的风险预期。

如果 cpc 是离散值且非负数,您可以将其解释为计数并使用零膨胀泊松模型。如果不是,您可以通过四舍五入到最接近的分或类似的东西来转换它。

您询问了“久经考验”的方法,因此我建议使用逻辑回归。

我还不熟悉 TF,所以不确定这种方法在那里是否容易实现。

下面是解释如何使用 R 的 glm 执行此操作的答案的链接:简而言之,除了指定响应列(介于 0 和 1 之间的比率)之外,您还必须提供表示试验总数的权重列。

如何对分数结果进行逻辑回归

一种可能性是采用具有独立分类和回归头的障碍模型。分类应理解为产品是否已售出(非零回归值)或未售出(回归值为零)。好处是可以手动将回归值归零,以防分类器投票给负类。tf.keras例如,这是一个适用于图像回归的双头模型。

from tensorflow.keras.layers import *
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.applications import ResNet50

...

input_shape = (256,256,3)
inputs = Input(input_shape)

# feature extration
base_model = ResNet50(
    input_shape=input_shape,
    weights='imagenet',
    include_top=False,
)
base_model = base_model(inputs)

# bottleneck
bottleneck = GlobalAveragePooling2D()(base_model)
bottleneck = Dense(256, activation='relu')(bottleneck)
bottleneck = Dropout(0.25)(bottleneck)

# classification head
clf = Dense(32, activation='relu')(bottleneck)
clf = Dropout(0.5)(clf)
clf = Dense(1, use_bias=False)(clf)
clf_output = Activation("sigmoid", name="clf_head_output")(clf)

# regression head
regr = Dense(32, activation='relu')(bottleneck)
regr = Dropout(0.5)(regr)
regr = Dense(1, use_bias=False)(regr)
regr_output = Activation("relu", name="regr_head_output")(regr) #<- change activation according to your task

# build model
model = Model(inputs=[inputs], outputs=[regr_output, clf_output,])

通常会选择mean_absolute_errormean_squared_error作为回归输出损失。在 ZIP(零膨胀泊松)分布的情况下,您可能面临的问题是模型的预测可能往往低于基本事实,尤其是对于最高回归值。如果是这种情况,那么这可能是因为模型因预测错误的高回归值而受到最大的惩罚。

标准化回归输出很重要,可以尝试诸如boxcox 之类的技巧,但这可能很困难,请记住零在分布中具有特殊作用。如果回归任务有一定的下限(L)和上限(U),对我来说效果很好的一个技巧是将输出标准化为区间 [0,1] 并改用角度回归。这个想法是,然后原始 L 和 U 将彼此相同(回归值位于单位圆上)并且模型无论尝试从“上方”还是“下方”接近高/稀有值都会受到同等惩罚. 这也是我对tf.keras. 我建议使用这种方法使用sigmoid剪裁relu(with max_value=1.)。

import tensorflow as tf
import tensorflow.keras.backend as K

PI = tf.constant(math.pi)
def angular_l1(y_true, y_pred): #y_true and y_pred should be in the inteval [0,1]
    y_true = y_true*2*PI #<- scale values to [0,2pi]
    y_pred = y_pred*2*PI #<- scale values to [0,2pi]
    return K.mean(K.abs(tf.math.atan2(K.sin(y_true - y_pred), K.cos(y_true - y_pred))))