如何按r_count扩展DataFrame并随机分配col值至value_1列
Python Pandas: Expand Rows by Count and Distribute Column Value Randomly
问题回顾
你有一个原始DataFrame df1,需要生成新的df2满足以下要求:
- 按每行的
r_count值扩展对应行(比如第一行扩展为22条记录) - 新增
value_1列,所有扩展行的value_1总和等于原行的col值,且为随机分配而非均分 - 其余列保持与
df1一致
原始df1的数据可通过以下代码构造:
import pandas as pd data = { 'F_Date': ['01/09/2019']*13, 'Booking_Date': ['02/08/2019', '03/08/2019', '04/08/2019', '06/08/2019', '09/08/2019', '10/08/2019', '11/08/2019', '12/08/2019', '13/08/2019', '14/08/2019', '15/08/2019', '16/08/2019', '17/08/2019'], 'col': [70,73,76,79,82,86,89,93,97,101,106,110,115], 'r_count': [22,12,9,6,5,4,4,4,4,4,3,3,4] } df1 = pd.DataFrame(data)
解决方案
我提供两种实现方式,第一种简洁高效,第二种可以严格保证value_1总和与原col值完全相等(避免浮点误差)。
方法一:简洁版(随机分配,总和近似相等)
这种方法利用numpy生成随机数并归一化,快速实现需求:
import numpy as np def expand_row(row): # 生成r_count个0-1之间的随机数 random_vals = np.random.rand(row['r_count']) # 归一化处理,让随机数总和等于原行的col值 normalized_vals = random_vals / random_vals.sum() * row['col'] # 构造扩展后的行数据 return pd.DataFrame({ 'F_Date': [row['F_Date']]*row['r_count'], 'Booking_Date': [row['Booking_Date']]*row['r_count'], 'col': [row['col']]*row['r_count'], 'r_count': [row['r_count']]*row['r_count'], 'value_1': normalized_vals }) # 应用函数到每一行并合并结果 df2 = pd.concat(df1.apply(expand_row, axis=1).tolist(), ignore_index=True)
说明:
np.random.rand()生成的随机数分布均匀,归一化后可以保证总和接近原col值(因为浮点精度问题可能有极小误差)- 这种方法代码简洁,适合对精度要求不是极高的场景
方法二:严格精度版(总和完全等于col)
如果需要value_1的总和严格等于原col值,且保留指定小数位数(比如两位),可以用这个方法:
def expand_row_precise(row): n = row['r_count'] # 如果r_count为1,直接返回原col值 if n == 1: return pd.DataFrame({ 'F_Date': [row['F_Date']], 'Booking_Date': [row['Booking_Date']], 'col': [row['col']], 'r_count': [row['r_count']], 'value_1': [row['col']] }) # 生成n-1个随机数,归一化后调整总和小于col random_vals = np.random.rand(n-1) scaled_vals = random_vals / random_vals.sum() * (row['col'] - 0.01) # 留余量避免溢出 scaled_vals = scaled_vals.round(2) # 计算最后一个值,确保总和严格等于col last_val = row['col'] - scaled_vals.sum() last_val = round(last_val, 2) # 合并所有value_1值 value_1 = np.append(scaled_vals, last_val) # 构造扩展后的行 return pd.DataFrame({ 'F_Date': [row['F_Date']]*n, 'Booking_Date': [row['Booking_Date']]*n, 'col': [row['col']]*n, 'r_count': [row['r_count']]*n, 'value_1': value_1 }) df2_precise = pd.concat(df1.apply(expand_row_precise, axis=1).tolist(), ignore_index=True)
说明:
- 先生成前
n-1个随机值,再通过计算得到最后一个值,确保总和严格等于原col值 - 使用
round(2)保留两位小数,符合常见的数值展示需求
验证结果
你可以通过以下代码验证value_1的总和是否符合要求:
# 验证某一行的value_1总和 sample_booking_date = '02/08/2019' original_col = df1[df1['Booking_Date'] == sample_booking_date]['col'].values[0] sum_value1 = df2_precise[df2_precise['Booking_Date'] == sample_booking_date]['value_1'].sum() print(f"原col值: {original_col}, value_1总和: {sum_value1}")
内容的提问来源于stack exchange,提问作者vp7
相关产品推荐
相关产品推荐

