按分類樣本數占比生成並隨機獲取樣本數據
By:授客 QQ:1033553122
開發環境
win 10
python 3.6.5
需求
已知樣本分類,每種分類的樣本占比數,及樣本總數,需要隨機獲取這些分類的樣本。比如,我有4種任務,分別為任務A,任務B,任務C,任務D, 每種任務需要重復執行的總次數為1000,每次執行隨機獲取一種任務來執行,不同分類任務執行次數占比為 A:B:C:D = 3:5:7:9
代碼實現
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'shouke'
import random
def get_class_instance_by_proportion(class_proportion_dict, amount):
"""
根據每種分類的樣本數比例,及樣本總數,為每每種分類構造樣本數據
class_proportion_dict: 包含分類及其分類樣本數占比的字典:{"分類(id)": 分類樣本數比例}
amount: 所有分類的樣本數量總和
返回一個列表:包含所有分類樣本的list
"""
bucket = []
proportion_sum = sum([weight for group_id, weight in class_proportion_dict.items()])
residuals = {} # 存放每種分類的樣本數計算差值
for class_id, weight in class_proportion_dict.items():
percent = weight / float(proportion_sum)
class_instance_num = int(round(amount * percent))
bucket.extend([class_id for x in range(class_instance_num)])
residuals[class_id] = amount * percent - round(amount * percent)
if len(bucket) < amount:
# 計算獲取的分類樣本總數小於給定的分類樣本總數,則需要增加分類樣本數,優先給樣本數計算差值較小的分類增加樣本數,每種分類樣本數+1,直到滿足數量為止
for class_id in [l for l, r in sorted(residuals.items(), key=lambda x: x[1], reverse=True)][: amount - len(bucket)]:
bucket.append(class_id)
elif len(bucket) > amount:
# # 計算獲取的分類樣本總數大於給定的分類樣本總數,則需要減少分類樣本數,優先給樣本數計算差值較大的分類減少樣本數,每種分類樣本數-1,直到滿足數量為止
for class_id in [l for l, r in sorted(residuals.items(), key=lambda x: x[1])][: len(bucket) - amount]:
bucket.remove(class_id)
return bucket
class A:
def to_string(self):
print('A class instance')
class B:
def to_string(self):
print('B class instance')
class C:
def to_string(self):
print('C class instance')
class D:
def to_string(self):
print('D class instance')
classes_map = {1: A, 2: B, 3:C, 4: D}
class_proportion_dict = {1: 3, 2: 5, 3:7, 4: 9} # {分類id: 樣本數比例} ,即期望4個分類的樣本數比例為為 3:5:7:9
class_instance_num = 1000 # 樣本總數
result_list = get_class_instance_by_proportion(class_proportion_dict, class_instance_num)
for class_id in class_proportion_dict:
print('%s %s' % (classes_map[class_id], result_list.count(class_id)))
# 制造樣本並隨機獲取樣本
random.shuffle(result_list)
while result_list:
class_id = random.sample(result_list, 1)[0]
classes_map[class_id]().to_string()
result_list.remove(class_id)
運行結果
說明
以上方式大致實現思路就是在知道總樣本數的情況下,提前為每種分類生成樣本,然后隨機獲取,按這種方式可以實現比較准確的結果,但是得提前知道樣本總數及不同分類樣本數占比