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

如何在Numpy与Pandas中逐行正确使用np.select()方法?

问题:基于Target逐行为零售商计算分数时的np.select报错解决

我需要根据零售商标记的target(分为balanced多维度通用分数、nmv聚焦高NMV零售商两类),为每个零售商生成聚类用的分数。尝试用df.iterrows()逐行循环结合np.select()赋值时,抛出错误:

ValueError: Must have equal len keys and value when setting with an iterable

原代码实现

targets = ['balanced','nmv'] 

day_of_month = date.today().day

df['Score'] = 0

if day_of_month > 10: # 每月10号后执行动态打分逻辑,否则执行月初计划

    for index, row in df.iterrows():
        target = row['target']

        if target == 'balanced':
            conditions = [
                (df['retailer_id'].isin(droppers['retailer_id'])), # 已从MP移除的零售商

                (df['months_sr'] > 0.4) | (df['historical_sr'] > 0.4) & (df['orders_this_month_total'] >= 1), 
                
                (df['wallet_amount'] > 0) & (df['orders_this_month_total'] > 0), # 有余额但本月无订单

                (df['orders_this_month_total'] == 1), # 本月仅下单一次
                
                ( (df[['nmv_this_month_total','nmv_one_month_ago_total','nmv_two_months_ago_total','nmv_three_months_ago_total']].fillna(0).pct_change(axis = 1).mean(axis = 1) ) > 0), # NMV呈增长趋势

                (df['skus_pct_change_q_cut'].isin(['med','high','extreme'])), # 订单SKU数量更可能超过3个

                (df['orders_one_month_ago_total'] >= 1) & (df['orders_this_month_total'] <= 1), # 上月有下单,本月下单≤1次

                (df[['orders_one_month_ago_total','orders_two_months_ago_total','orders_three_months_ago_total']].sum(axis = 1) > 0) & (df['orders_this_month_total'] >= 1), # 近三月至少有一个月下单,且本月有下单

                (df[['orders_one_month_ago_total','orders_two_months_ago_total','orders_three_months_ago_total']].sum(axis = 1) > 0) & (df['orders_this_month_total'] <= 1), # 近三月至少有一个月下单,但本月下单≤1次

                (df['sessions_this_month'] > 0) & (df['visits_this_month'] == 0), # 打开过APP但未被拜访
                
                (df['visits_this_month'] == 0) & (df['peak_week'] == wom) & ((df['months_sr'] >= 0.4) & (df['months_sr'] <= 1)) & (df['orders_this_month_total'] < 4), # 本周是高峰周且下单量<4

                (df['peak_week']  < wom) & (df['orders_this_month_total'] == 0), # 错过高峰周且本月无订单

                (df['wallet_amount'] > 0),

                True
            ]
            results = list(range(len(conditions) - 1, -1, -1))  # balanced目标的分数映射
        
        elif target == 'nmv':
            
            conditions = [
                (df['retailer_id'].isin(droppers['retailer_id'])), # 已从MP移除的零售商 
                        
                (df['visits_this_month'] == 0) & (df['peak_week'] == wom) & ((df['months_sr'] >= 0.4) & (df['months_sr'] <= 1)) & (df['orders_this_month_total'] == 0), # 本周是高峰周且无订单

                (df['visits_this_month'] == 0) & (df['historical_sr'] >= 0.4) & (df['orders_this_month_total'] == 0), # 整体转化率≥40%且本月无订单

                (df['nmv_q_cut_total'].isin(['high','extreme'])),
                
                (df['nmv_q_cut_total'].isin(['high','extreme'])) & ( (df['wallet_amount'] > 0) | (df['n_offers'] > 0) ),

                (df['months_nmv'].median() >= df['polygon_average_nmv']),

                (df['orders_one_month_ago'] > 0),

                (df['months_sessions_q_cut'] > 0),

                True
            ]
            results = list(range(len(conditions) - 1, -1, -1)) # nmv目标的分数映射

        df.loc[index, 'Score'] = np.select(conditions, results)
        df['Score'] = df['Score'].astype(int)

else:

    conditions = [
        (df['retailer_id'].isin(droppers['retailer_id'])), # 已从MP移除的零售商 
                
        (df['visits_this_month'] == 0) & (df['peak_week'] == wom) & ((df['months_sr'] >= 0.4) & (df['months_sr'] <= 1)), # 本周是高峰周 

        (df['historical_sr'] >= 0.4), # 整体转化率≥40%
        
        (df['orders_one_month_ago'].isin([1,2,3,4])) & (df['nmv_one_month_ago'] >= 1500), 

        (df['orders_one_month_ago'].isin([1,2,3,4])),

        (df['orders_two_months_ago'].isin([1,2,3,4])),

        (df['orders_three_months_ago'].isin([1,2,3,4])),

        (df['last_visit_date'].dt.year == 2022) & (df['last_order_date'].dt.year == 2022), # 最后拜访和下单都在2022年

        (df['last_visit_date'].dt.year == 2023) & (df['last_order_date'].dt.year == 2023),
        
        True
    ]

    results = list(range(len(conditions) - 1, -1, -1))

    df['Score'] = np.select(conditions, results)

错误原因

你在iterrows()循环中,conditions是基于整个DataFrame生成的布尔数组(长度等于df总行数),但试图将np.select()返回的整个数组结果赋值给单行df.loc[index, 'Score'],导致长度不匹配,触发报错。

正确解决方法

放弃逐行循环,利用Pandas的向量化操作,按target分组处理所有对应行,效率更高且避免错误:

import pandas as pd
import numpy as np
from datetime import date

targets = ['balanced','nmv'] 
day_of_month = date.today().day
df['Score'] = 0

if day_of_month > 10:
    # 处理balanced目标的所有行
    balanced_mask = df['target'] == 'balanced'
    if balanced_mask.any():
        # 预计算重复使用的统计量
        nmv_pct_mean = df[['nmv_this_month_total','nmv_one_month_ago_total','nmv_two_months_ago_total','nmv_three_months_ago_total']].fillna(0).pct_change(axis=1).mean(axis=1)
        prev_orders_sum = df[['orders_one_month_ago_total','orders_two_months_ago_total','orders_three_months_ago_total']].sum(axis=1)
        
        balanced_conditions = [
            df['retailer_id'].isin(droppers['retailer_id']),
            (df['months_sr'] > 0.4) | (df['historical_sr'] > 0.4) & (df['orders_this_month_total'] >= 1),
            (df['wallet_amount'] > 0) & (df['orders_this_month_total'] > 0),
            df['orders_this_month_total'] == 1,
            nmv_pct_mean > 0,
            df['skus_pct_change_q_cut'].isin(['med','high','extreme']),
            (df['orders_one_month_ago_total'] >= 1) & (df['orders_this_month_total'] <= 1),
            (prev_orders_sum > 0) & (df['orders_this_month_total'] >= 1),
            (prev_orders_sum > 0) & (df['orders_this_month_total'] <= 1),
            (df['sessions_this_month'] > 0) & (df['visits_this_month'] == 0),
            (df['visits_this_month'] == 0) & (df['peak_week'] == wom) & ((df['months_sr'] >= 0.4) & (df['months_sr'] <= 1)) & (df['orders_this_month_total'] < 4),
            (df['peak_week'] < wom) & (df['orders_this_month_total'] == 0),
            df['wallet_amount'] > 0,
            True
        ]
        balanced_results = list(range(len(balanced_conditions)-1, -1, -1))
        df.loc[balanced_mask, 'Score'] = np.select(balanced_conditions, balanced_results)[balanced_mask]

    # 处理nmv目标的所有行
    nmv_mask = df['target'] == 'nmv'
    if nmv_mask.any():
        nmv_conditions = [
            df['retailer_id'].isin(droppers['retailer_id']),
            (df['visits_this_month'] == 0) & (df['peak_week'] == wom) & ((df['months_sr'] >= 0.4) & (df['months_sr'] <= 1)) & (df['orders_this_month_total'] == 0),
            (df['visits_this_month'] == 0) & (df['historical_sr'] >= 0.4) & (df['orders_this_month_total'] == 0),
            df['nmv_q_cut_total'].isin(['high','extreme']),
            df['nmv_q_cut_total'].isin(['high','extreme']) & ((df['wallet_amount'] > 0) | (df['n_offers'] > 0)),
            df['months_nmv'].median() >= df['polygon_average_nmv'],
            df['orders_one_month_ago'] > 0,
            df['months_sessions_q_cut'] > 0,
            True
        ]
        nmv_results = list(range(len(nmv_conditions)-1, -1, -1))
        df.loc[nmv_mask, 'Score'] = np.select(nmv_conditions, nmv_results)[nmv_mask]

    df['Score'] = df['Score'].astype(int)
else:
    # 月初逻辑保持不变,本身就是向量化操作
    conditions = [
        df['retailer_id'].isin(droppers['retailer_id']),
        (df['visits_this_month'] == 0) & (df['peak_week'] == wom) & ((df['months_sr'] >= 0.4) & (df['months_sr'] <= 1)),
        df['historical_sr'] >= 0.4,
        (df['orders_one_month_ago'].isin([1,2,3,4])) & (df['nmv_one_month_ago'] >= 1500),
        df['orders_one_month_ago'].isin([1,2,3,4]),
        df['orders_two_months_ago'].isin([1,2,3,4]),
        df['orders_three_months_ago'].isin([1,2,3,4]),
        (df['last_visit_date'].dt.year == 2022) & (df['last_order_date'].dt.year == 2022),
        (df['last_visit_date'].dt.year == 2023) & (df['last_order_date'].dt.year == 2023),
        True
    ]
    results = list(range(len(conditions)-1, -1, -1))
    df['Score'] = np.select(conditions, results)

关键优化点

  • 用布尔掩码(balanced_mask/nmv_mask)筛选对应target的行,一次性处理所有符合条件的记录,避免逐行循环的性能损耗和错误
  • 预计算需要重复使用的统计量(如nmv_pct_mean),提升代码效率
  • 保持np.select()的向量化特性,确保返回结果与目标行长度匹配

内容的提问来源于stack exchange,提问作者Esmael Awad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 22:54:55