生成带列上下限且行和为100的随机DataFrame遇求和精度问题
问题:生成满足列上下限且行和接近100的DataFrame
我需要生成一个填充随机浮点数的DataFrame,要求:
- 每列的值由给定的元组列表定义上下限
- 每行的求和结果需落在99.9到100.1之间(公差0.1)
但当前实现的部分行和达不到99.99及以上,代码如下:
import pandas as pd import numpy as np num_rows = 150 num_cols = 15 bounds = [(0, 20), (0, 10), (0, 15), (0, 5), (0, 10), (0, 5), (0, 20), (0, 10), (0, 10), (0, 5), (0, 5), (0, 10), (0, 5), (0, 10), (0, 10)] tolerance = 0.1 df = pd.DataFrame(np.zeros((num_rows, num_cols))) num_generated_rows = 0 while num_generated_rows < num_rows: for row in range(num_generated_rows, num_rows): row_sum = 0 for col in range(num_cols): lower, upper = bounds[col] remaining_cols = num_cols - col - 1 remaining_sum = 100 - row_sum if remaining_cols > 0: min_possible_value = max(0, remaining_sum - remaining_cols * upper) max_possible_value = min(upper, remaining_sum - remaining_cols * lower) else: min_possible_value = max(0, 100 - row_sum - upper) max_possible_value = min(upper, 100 - row_sum - lower) value = np.random.uniform(min_possible_value, max_possible_value) df.iloc[row, col] = value row_sum += value # Check if the row sum is within the defined tolerance if abs(row_sum - 100) <= tolerance: num_generated_rows += 1 break # Stop generating rows if we've reached the desired number if num_generated_rows == num_rows: break df = df.sample(frac=1).reset_index(drop=True)
问题分析
- 最后一列计算逻辑错误:处理最后一列(
remaining_cols=0)时,原代码的取值范围计算混乱,导致最后一列无法精准将行和拉到100附近。 - 无有效性校验:前面列的随机取值可能导致剩余总和无法满足后续列的上下限约束,此时继续生成会得到无效行,但原代码没有提前终止并重置该行的逻辑。
修正后的代码
import pandas as pd import numpy as np num_rows = 150 num_cols = 15 bounds = [(0, 20), (0, 10), (0, 15), (0, 5), (0, 10), (0, 5), (0, 20), (0, 10), (0, 10), (0, 5), (0, 5), (0, 10), (0, 5), (0, 10), (0, 10)] tolerance = 0.1 df = pd.DataFrame(np.zeros((num_rows, num_cols))) num_generated_rows = 0 while num_generated_rows < num_rows: row_sum = 0 valid_row = True row_data = [] for col in range(num_cols): lower, upper = bounds[col] remaining_cols = num_cols - col - 1 # 计算当前列的合法取值范围:兼顾自身上下限和剩余列的约束 min_val = max(lower, 100 - row_sum - remaining_cols * upper) max_val = min(upper, 100 - row_sum - remaining_cols * lower) # 若当前列无合法取值,直接放弃该行,重新生成 if min_val > max_val: valid_row = False break # 最后一列直接取刚好凑够100的值(钳位到列的上下限内) if remaining_cols == 0: val = 100 - row_sum val = max(lower, min(upper, val)) else: val = np.random.uniform(min_val, max_val) row_data.append(val) row_sum += val # 验证行和符合要求后,存入DataFrame if valid_row and abs(row_sum - 100) <= tolerance: df.iloc[num_generated_rows] = row_data num_generated_rows += 1 # 打乱行顺序 df = df.sample(frac=1).reset_index(drop=True) # 可选:验证行和分布 print("行和统计信息:") print(df.sum(axis=1).describe())
修正说明
- 精准控制最后一列:最后一列不再随机取值,直接计算为
100 - row_sum并钳位到列的上下限内,确保行和尽可能接近100。 - 提前终止无效行生成:当某一列无合法取值范围时,直接放弃当前行的生成,避免无效计算。
- 优化取值范围计算:每列的最小/最大值同时考虑自身上下限和剩余列的约束,确保后续列有足够空间满足要求。
内容的提问来源于stack exchange,提问作者user21342619
相关产品推荐
相关产品推荐

