#P3629. 第2题-大促活动入场决策
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 14
            Accepted: 7
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年9月9日-菜鸟
                              
                      
          
 
- 
                        算法标签>决策树          
 
第2题-大促活动入场决策
思路
这个问题的核心是模拟决策树(特别是CART算法)在选择最佳分裂特征时的过程。决策树在构建时,需要在每个节点上选择一个特征进行分裂,目标是让分裂后的数据子集“纯度”尽可能高。 基尼指数就是衡量数据纯度的一种指标。一个集合的基尼指数越小,其纯度越高。
题目要求我们找到使整个数据集在分裂后基尼指数最小的那个特征。解题的整体思路如下:
- 
遍历所有特征:我们需要对数据集的每一个特征(即输入二维
list中每个子list的除了最后一个元素之外的其它元素)进行评估。 - 
计算每个特征的条件基尼指数:对于每一个特征
A,我们需要计算如果用它来分裂数据集,最终得到的条件基尼指数 Gini(D∣A) 是多少。- 
确定分裂点:一个特征可能有多个不同的取值。题目中的描述是“根据特征
A是否取某一值a被分割为 D1,D2”。这意味着对于特征A的每一个唯一值a,我们都可以进行一次二元分裂:- 子集 D1:特征 
A的值等于a的所有样本。 - 子集 D2:特征 
A的值不等于a的所有样本。 
 - 子集 D1:特征 
 - 
选择特征的最佳分裂:一个特征可能会因为其不同的取值而产生多个不同的条件基尼指数。例如,如果一个特征有
v1, v2, v3三个值,我们可以分别计算按v1分裂、按v2分裂、按v3分裂后的基尼指数。该特征最终的评判指标,是这所有可能分裂中产生的最小的那个基尼指数。 
 - 
 - 
比较并找出最优特征:我们依次计算出每个特征的最小条件基尼指数,然后比较这些值。值最小的那个特征,就是我们要找的最佳分裂特征。我们返回该特征的索引即可。
 - 
处理特殊情况:
- 如果一个分裂产生的子集为空,其基尼指数为0。
 - 如果一个特征的所有值都相同,那么无论如何分裂,都会导致一个子集为空,另一个子集是全集。这种分裂是没有意义的,其条件基尼指数等于未分裂前的总基尼指数。
 - 如果多个特征算出的最小基尼指数相同,根据题目样例和常规算法实践,选择索引靠前的那个特征。
 
 
好的,这是一个不包含任何中文提示,可以直接运行并处理输入的版本。
将以下代码复制并运行。您可以直接粘贴完整的二维列表(例如 [[0,0,0,0,0],[0,0,0,1,0],[0,1,0,1,1],[0,1,1,0,0],[0,0,0,0,0]])到终端,然后按 Enter,再按 Ctrl+D (Linux/macOS) 或 Ctrl+Z + Enter (Windows) 来结束输入并查看结果。
python
import sys
import numpy as np
from collections import Counter
def calculate_gini(labels):
    """
    计算一个数据子集的基尼指数。
    """
    if len(labels) <= 1:
        return 0.0
    
    counts = Counter(labels)
    total_samples = len(labels)
    
    gini = 1.0
    for count in counts.values():
        p = count / total_samples
        gini -= p ** 2
        
    return gini
def find_best_feature(data):
    """
    找到使整个数据集合基尼指数最小的特征对应的索引。
    """
    try:
        dataset = np.array(data)
    except ValueError:
        return -1 # 子列表长度不一致
    if dataset.ndim != 2 or dataset.shape[1] < 2:
        return -1 # 非二维或列数不足
    X = dataset[:, :-1]
    y = dataset[:, -1]
    
    num_samples, num_features = X.shape
    
    min_gini_value = float('inf')
    best_feature_idx = -1
    
    for i in range(num_features):
        feature_col = X[:, i]
        unique_values = np.unique(feature_col)
        
        if len(unique_values) <= 1:
            continue
            
        current_feature_min_gini = float('inf')
        
        for value in unique_values:
            mask = (feature_col == value)
            
            d1_labels = y[mask]
            d2_labels = y[~mask]
            
            if len(d1_labels) == 0 or len(d2_labels) == 0:
                continue
            
            gini1 = calculate_gini(d1_labels)
            gini2 = calculate_gini(d2_labels)
            
            p1 = len(d1_labels) / num_samples
            conditional_gini = p1 * gini1 + (1 - p1) * gini2
            
            if conditional_gini < current_feature_min_gini:
                current_feature_min_gini = conditional_gini
        if current_feature_min_gini < min_gini_value:
            min_gini_value = current_feature_min_gini
            best_feature_idx = i
            
    return best_feature_idx
def main():
    """
    主函数,用于读取输入并执行计算。
    """
    try:
        # 读取所有输入行并将其合并为一个字符串
        full_input_str = sys.stdin.read()
        # 使用 eval 将完整的字符串转换为 list 对象
        input_data = eval(full_input_str)
    except (SyntaxError, NameError):
        # 如果输入不是有效的 Python 列表格式,则不执行任何操作
        return
    # 检查是否成功解析为列表
    if not isinstance(input_data, list):
        return
    # 调用核心函数进行计算
    best_idx = find_best_feature(input_data)
    
    # 仅当找到有效索引时才打印结果
    if best_idx != -1:
        print(best_idx)
if __name__ == "__main__":
    main()
        题目内容
某电商平台计划向定向用户发起一次大促活动,向受邀用户定向投放活动入口。通过构建一系列特征,使用决策树对用户进行分类,被分类为正样本的用户可以获得入场资格。使用基尼指数作为特征的优先级决策指标,给定一个数据集,其基尼指数可以表示为:
Gini(D)=1−∑k=1k(∣D∣∣Ck∣)2
其中 Ck 代表的是属于某一类的样本个数,D 是整个数据集的样本数量,如果样本集合 D 根据特征 A 是否取某一值 a 被分割为 D1,D2 ,两部分,那么在特征 A 的条件下,集合的基尼指数可以定义为:
$Gini(D∣A)=\frac{∣D_1∣}{∣D∣}Gini(D_1)+\frac{∣D_2∣}{∣D∣}Gini(D_2)$
现给定一个数据集,要求给出对于使整个集合基尼指数最小的特征,请结合题目信息,输入、输出和补充完成完成作答。
输入描述
输入一个二维 list ,每个子 list 最后一个元素是 label ,其他元素是对应特征的值。
输出描述
要求给出使整个数据集合基尼指数最小的特征对应的索引。
补充说明
(1)可以使用形如 numpy、pandas 的第三方代码库。
(2)为了保证唯一性,请严格遵循输入输出描述进行作答。
(3)形如 sys.stdin 等方法结合 for 循环和 eval 函数即可读取并还原输入数据。
样例1
输入
[[0,0,0,0,0],[0,0,0,1,0],[0,1,0,1,1],[0,1,1,0,0],[0,0,0,0,0]]
输出
1
说明
第 2 列特征下,整个集合对应的基尼指数最小,其索引为 1 ,所以返回值为 1