求助:按指定规则为OrderID随机分配CustomerID的Python实现
嗨,我来帮你搞定这个需求!你要的是给OrderID随机分配CustomerID,同时满足两个核心规则:同一OrderID必须绑定同一个CustomerID,每个CustomerID的使用次数(不管是对应同一个订单的多行还是多个订单)不能超过5次。
我猜你用np.random的时候可能没处理好“同一OrderID对应相同CustomerID”的映射关系,或者没控制住CustomerID的重复次数上限。下面给你两种场景的解决方案,对应你描述里的两种可能理解:
场景1:每个CustomerID最多对应5个不同的OrderID(允许同一CustomerID的总行数超过5)
这种场景下,只要一个CustomerID绑定的唯一OrderID数量不超过5就行,比如示例里123绑定了A01和A03两个OrderID,总行数3次是允许的。
实现代码(用Pandas+Numpy)
import pandas as pd import numpy as np import math # 假设你的原始数据是这样的DataFrame(可以替换成你自己的数据) df = pd.DataFrame({ 'OrderID': ['A01', 'A01', 'A02', 'A03', 'A02', 'A04', 'A05', 'A06', 'A07', 'A08', 'A09', 'A10', 'A11'] }) # 步骤1:提取所有唯一的OrderID并随机打乱(保证分配的随机性) unique_orders = df['OrderID'].unique() np.random.shuffle(unique_orders) # 步骤2:计算需要的CustomerID数量(每个最多绑定5个OrderID) max_orders_per_customer = 5 num_customers = math.ceil(len(unique_orders) / max_orders_per_customer) # 步骤3:生成CustomerID列表,每个ID重复最多5次,刚好覆盖所有唯一OrderID customer_ids = [] for cid in range(1, num_customers + 1): # 每次添加不超过5个,直到总数量匹配唯一OrderID的数量 add_num = min(max_orders_per_customer, len(unique_orders) - len(customer_ids)) customer_ids.extend([cid] * add_num) # 步骤4:创建OrderID到CustomerID的映射字典 order_customer_map = dict(zip(unique_orders, customer_ids)) # 步骤5:把映射应用到原始数据 df['CustomerID'] = df['OrderID'].map(order_customer_map) # 验证结果 print("每个CustomerID绑定的唯一OrderID数量:") print(df.groupby('CustomerID')['OrderID'].nunique()) print("\n同一OrderID是否都对应同一个CustomerID:") print(df.groupby('OrderID')['CustomerID'].nunique().max() == 1) # 应该输出True
场景2:每个CustomerID的总行数不超过5次(更严格的限制)
如果你的需求是CustomerID在整个数据里出现的总行数不能超过5(比如一个客户最多有5行记录,不管是一个订单还是多个订单),那需要用贪心+随机的方式分配:
实现代码
import pandas as pd import numpy as np # 原始数据 df = pd.DataFrame({ 'OrderID': ['A01', 'A01', 'A02', 'A03', 'A02', 'A04', 'A05'] }) # 步骤1:统计每个OrderID的出现次数,并随机打乱顺序(保证分配随机) order_counts = df['OrderID'].value_counts().reset_index() order_counts.columns = ['OrderID', 'RowCount'] order_counts = order_counts.sample(frac=1, random_state=np.random.randint(1000)).reset_index(drop=True) # 步骤2:初始化CustomerID的使用追踪器和映射字典 customer_usage = {} # key: CustomerID, value: 已使用的总行数 current_cid = 1 order_customer_map = {} # 步骤3:给每个OrderID分配CustomerID for _, row in order_counts.iterrows(): order_id = row['OrderID'] needed_rows = row['RowCount'] # 找出所有还有剩余容量(5-已用行数 >= 需要的行数)的CustomerID available_cids = [cid for cid, used in customer_usage.items() if (5 - used) >= needed_rows] if available_cids: # 随机选一个可用的CustomerID selected_cid = np.random.choice(available_cids) else: # 没有可用的,新建一个CustomerID selected_cid = current_cid customer_usage[selected_cid] = 0 current_cid += 1 # 更新该CustomerID的使用次数 customer_usage[selected_cid] += needed_rows order_customer_map[order_id] = selected_cid # 步骤4:应用映射到原始数据 df['CustomerID'] = df['OrderID'].map(order_customer_map) # 验证结果 print("每个CustomerID的总行数:") print(df['CustomerID'].value_counts()) print("\n同一OrderID是否都对应同一个CustomerID:") print(df.groupby('OrderID')['CustomerID'].nunique().max() == 1) # 应该输出True
这两种方案都能解决你的问题,你可以根据实际需求选择。核心思路都是先建立OrderID到CustomerID的映射关系,再把映射应用到原始数据,这样就能保证同一OrderID对应相同的CustomerID,同时控制住CustomerID的使用次数上限。
内容的提问来源于stack exchange,提问作者dennis
相关产品推荐
相关产品推荐

