Yêu cầu thg 8 28, 2018 10:00 SA 1961 1 1
  • 1961 1 1
+1

[PHP] Random đánh trọng số

Chia sẻ
  • 1961 1 1

Mình đang làm về random item, có thể điều chỉnh phần trăm tỉ lệ ra của item! Hiện tại mình đang làm theo cách này để lấy random 1 item nhưng thấy không được ngẫu nhiên như mong muốn. vì nó luôn ưu tiên item sắp xếp theo thứ tự đầu -> cuối.
Ví dụ: mình có 4 item và đánh trọng số là

$list_item = {
                {'name' => A, 'number' =>50},
                {'name' => B, 'number' =>25},
                {'name' => C, 'number' =>15},
                {'name' => D, 'number' =>10},
             }

Cách mình làm:

$sum = 50 + 25 + 15 + 10;

$rand = mt_rand(1,$sum);

foreach($list_item as $item){
    $rand -= $item->number;
    if($rand < 0){
        return $item->name;
    }
}

Mong muốn: ngẫu nhiên theo tỉ lệ và 1 cách tốt hơn

1 CÂU TRẢ LỜI


Đã trả lời thg 8 28, 2018 10:05 SA
Đã được chấp nhận
+2

Trước đây mình cũng có từng gặp bài toán này, và đã viết một package composer để có thể dùng lại trong các project khác nhau, bạn có thể tham khảo tại wataridori/bias-random 😄

Install

composer require wataridori/bias-random

Usage

$biasRandom = new wataridori/BiasRandom/BiasRandom();
$data = [
    'wataridori' => 10,
];
$biasRandom->setData($data);
$biasRandom->addElement('Tran', 20);
$biasRandom->addElement('Duc', 30);
$biasRandom->addElement('Thang', 40);

// Random one element with weight.
$biasRandom->random();

// Random two elements
$biasRandom->random(2);

Về source code, bạn có thể xem ở đây

P/S: Mình thấy cách bạn đang làm cũng ổn mà nhỉ, sao bạn lại nghĩ là nó đang ưu tiên thứ tự từ trên xuống 🤔 (mà trong object ví dụ của bạn thì tỉ lệ được sắp xếp theo thứ tự từ trên xuống, nên ra kết quả ưu tiên từ trên xuống cũng là đúng mà nhỉ :v)

Chia sẻ
Avatar Tuấn AnhNguyễn @anhnguyen1494
thg 8 28, 2018 10:41 SA

Cái này mình đọc source của nó r =))) Chỉ muốn tìm hiểu thêm xem có giải thuật nào hay hơn và hiệu quả hơn ấy mà ! Qua rất nhiều lần test thì thấy cách nó lấy random k đc ngẫu nhiên theo tỉ lệ lắm =))) nên hoài nghi về thuật toán thôi. Xem có ai có cách khác không

Avatar Tran Duc Thang @thangtd90
thg 8 29, 2018 1:19 SA

@anhnguyen1494

Qua rất nhiều lần test thì thấy cách nó lấy random k đc ngẫu nhiên theo tỉ lệ lắm =)))

Không biết bạn test như thế nào, và tại sao lại nghĩ rằng nó "không được ngẫu nhiên theo tỉ lệ" nhỉ 🤔

Mình có viết một đoạn code sau để thử benchmark xem sao:

function testRandom() {
	$data = [
		'first' => 25,
		'second' => 10,
		'third' => 15,
		'forth' => 50,
	];

	$biasRandom = new wataridori\BiasRandom\BiasRandom();
	$results = [];

	for ($i = 0; $i < 1000000; $i++) {
		$biasRandom->setData($data);
		$randomElements = $biasRandom->random();
		$randomElement = $randomElements[0];
		$results[$randomElement] = isset($results[$randomElement]) ? $results[$randomElement] + 1 : 1;
	}

	foreach ($results as $key => $value) {
		echo $key . ' :' . $value . ' times (' . $value / 1000000 * 100 . "%)\n";
	}
}

Hàm testRandom sẽ thực hiện việc random 1 triệu lần, và thống kê các kết quả của các lần random đó, để xem tỉ lệ xuất hiện của chúng như thế nào.

Và dưới đây là kết quả mình nhận được:

>>> testRandom()
first :250419 times (25.0419%)
second :100027 times (10.0027%)
third :150592 times (15.0592%)
forth :498962 times (49.8962%)

>>> testRandom()
first :249364 times (24.9364%)
second :100401 times (10.0401%)
third :149683 times (14.9683%)
forth :500552 times (50.0552%)

>>> testRandom()
first :249564 times (24.9564%)
second :100380 times (10.038%)
third :150206 times (15.0206%)
forth :499850 times (49.985%)

>>> testRandom()
first :249771 times (24.9771%)
second :99763 times (9.9763%)
third :150445 times (15.0445%)
forth :500021 times (50.0021%)

>>> testRandom()
first :249949 times (24.9949%)
second :99740 times (9.974%)
third :150004 times (15.0004%)
forth :500307 times (50.0307%)

như bạn thấy, mình có chạy hàm testRandom 5 lần, và lần nào cũng ra kết quả khá chính xác với tỉ lệ mình vốn kỳ vọng ở nó, với độ chênh lệch trong khoảng trên dưới 0.05%. Mình nghĩ như vậy là tương đối ổn rồi chứ nhỉ 😂 không rõ bạn kỳ vọng chính xác đến mức nào nữa 🤔

Avatar Tuấn AnhNguyễn @anhnguyen1494
thg 8 29, 2018 1:41 SA

@thangtd90 Rất cảm ơn bạn đã cho mình thấy sự random của nó. giờ thì mình thấy nó đã đúng kì vọng của mình rồi 😂

Avatar Tran Duc Thang @thangtd90
thg 8 29, 2018 1:44 SA
Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí