You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TensorFlow多标签分类:NBA球员位置预测命中任意标签即正确

TensorFlow多标签NBA位置预测TypeError修复方案

问题场景

  • 目标:基于球员数据预测场上位置,数据集标注的是球员生涯出任过的所有位置组合,而非单一固定位置
  • 最初方案:将23种位置组合直接映射为1-23的整数值做单标签分类,代码可运行但不符合需求:
posdict = {'G-F' : 1, 'SG' : 2, 'SF' : 3, 'F' : 4, 'G' : 5, 'F-C' : 6, 'PG' : 7, 'F-G' : 8, 'C' : 9, 'PF' : 10, 'C-F' : 11, 'PF-C' : 12, 'SF-SG' : 13, 'C-PF' : 14, 'SG-SF' : 15, 'PF-SF' : 16, 'SF-PF' : 17, 'SG-PG' : 18, 'SF-PG' : 19, 'C-SF' : 20, 'PG-SG' : 21, 'PG-SF' : 22, 'SG-PF' : 23}
  • 实际需求:将所有位置归为5个基础类别(PG:1, SG:2, SF:3, PF:4, C:5),打过多个位置的球员对应多个有效标签,只要预测结果落在球员真实出任过的位置集合内就算预测正确。重构后的映射字典如下,替换后运行触发TypeError:
posdict = {'G-F' : [1,2,3,4], 'SG' : [2], 'SF' : [3], 'F' : [3,4], 'G' : [1,2], 'F-C' : [3,4,5], 'PG' : [1], 'F-G' : [1,2,3,4], 'C' : [5], 'PF' : [4], 'C-F' : [3,4,5], 'PF-C' : [4,5], 'SF-SG' : [2,3], 'C-PF' : [4,5], 'SG-SF' : [2,3], 'PF-SF' : [3,4], 'SF-PF' : [3,4], 'SG-PG' : [1,2], 'SF-PG' : [1,3], 'C-SF' : [3,5], 'PG-SG' : [1,2], 'PG-SF' : [1,3], 'SG-PF' : [2,4]}
  • 触发报错的原始代码(基于Estimator的单标签分类实现):
dftrain[('Pos')] = [posdict[item] for item in dftrain['Pos']]
dfeval[('Pos')] = [posdict[item] for item in dfeval['Pos']]

y_train = dftrain.pop('Pos')
y_eval = dfeval.pop('Pos')

NUMERICAL_COLUMS = ['G', 'PER', 'TS%', 'FTr', 'USG%', 'FG', 'FGA', 'FG%', '3P', '3PA', 'AST%', 'STL%', 'BLK%', 'TOV%', '2P', '2PA', 'OBPM', 'DBPM', 'BPM', '2P%', 'eFG%', 'FT', 'FTA', 'FT%', 'PTS', 'ORB%', 'DRB%', 'TRB%', 'OWS', 'DWS', 'WS']

feature_colums= []

for feature_name in NUMERICAL_COLUMS:
    feature_colums.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float64))

def make_input_fn(data_df, label_df, num_epochs=10, shuffle=True, batch_size=32):
  def input_function():
    ds = tf.data.Dataset.from_tensor_slices((dict(data_df), label_df))
    if shuffle:
      ds = ds.shuffle(1000)
    ds = ds.batch(batch_size).repeat(num_epochs)
    return ds
  return input_function

train_input_fn = make_input_fn(dftrain, y_train)
eval_input_fn = make_input_fn(dfeval, y_eval, num_epochs=1, shuffle=False)

linear_est = tf.estimator.LinearClassifier(feature_columns=feature_colums, n_classes=24)

linear_est.train(train_input_fn)
result = linear_est.evaluate(eval_input_fn)

print(result['accuracy'])

报错根因

  • 你用的tf.estimator.LinearClassifier是单标签多分类模型,只接受单个整数形式的标签输入,直接传入位置编号列表会触发类型错误
  • 代码里设置的n_classes=24是为之前23种位置组合的单分类任务配置的,和当前5个基础位置的多标签任务完全不匹配
  • 模型内置的accuracy指标仅支持“预测值与真实值完全相等”的判定逻辑,无法实现“预测值落在真实位置集合即算正确”的自定义规则

修复步骤

1. 标签转换为multi-hot格式

多标签任务不能直接传编号列表,要转为固定长度的multi-hot向量:向量长度为6(索引0留空,对齐你1-5的位置编号规则),球员打过的位置对应位设为1,其余设为0。比如同时打PG、SG的球员标签为[0,1,1,0,0,0]。

import numpy as np
def pos_to_multihot(pos_list):
    label = np.zeros(6, dtype=np.int32)
    for pos in pos_list:
        label[pos] = 1
    return label

dftrain['Pos'] = [pos_to_multihot(posdict[item]) for item in dftrain['Pos']]
dfeval['Pos'] = [pos_to_multihot(posdict[item]) for item in dfeval['Pos']]

y_train = np.array(dftrain.pop('Pos').tolist())
y_eval = np.array(dfeval.pop('Pos').tolist())

2. 替换为支持多标签的模型结构

LinearClassifier不支持多标签任务,新手更推荐用tf.keras实现,结构更简单易改:最后一层用5个sigmoid激活的神经元,每个神经元独立输出对应位置的出战概率。

import tensorflow as tf
from tensorflow.keras import layers

# 构建数值特征输入层
inputs = {col: layers.Input(name=col, shape=(), dtype=tf.float64) for col in NUMERICAL_COLUMS}
x = layers.concatenate(list(inputs.values()))
# 多标签输出层
outputs = layers.Dense(5, activation='sigmoid')(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

3. 自定义符合规则的准确率指标

不用内置的准确率,自己实现判定逻辑:取每个样本预测概率最高的位置,判断该位置是否在球员的真实位置集合中。

def custom_accuracy(y_true, y_pred):
    # 取预测概率最高的位置,+1对齐1-5的编号
    pred_pos = tf.argmax(y_pred, axis=1) + 1
    # 索引对应到multi-hot的位置,判断该位是否为1(即是否是真实打过的位置)
    pred_idx = tf.stack([tf.range(tf.shape(y_true)[0]), tf.cast(pred_pos, tf.int32)], axis=1)
    correct = tf.gather_nd(y_true, pred_idx)
    return tf.reduce_mean(tf.cast(correct, tf.float32))

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=[custom_accuracy]
)

4. 调整数据输入逻辑

不用原来的Estimator输入函数,直接用tf.data构造训练/验证集即可:

train_ds = tf.data.Dataset.from_tensor_slices((dict(dftrain), y_train)).shuffle(1000).batch(32).repeat(10)
eval_ds = tf.data.Dataset.from_tensor_slices((dict(dfeval), y_eval)).batch(32)

model.fit(train_ds, validation_data=eval_ds)
result = model.evaluate(eval_ds, return_dict=True)
print(result['custom_accuracy'])

后续如果需要输出球员所有可能的位置,只需要设置概率阈值(比如0.5),把概率超过阈值的位置都作为预测结果即可,自定义准确率的逻辑也可以对应调整为“预测结果和真实位置集合有交集就算正确”。

内容的提问来源于stack exchange,提问作者Doom Lord

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:45:31