Asked Aug 28th, 2018 10:00 AM 583 1 1
  • 583 1 1
0

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

Share
  • 583 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 ANSWERS


Answered Aug 28th, 2018 10:05 AM
Accepted
+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)

Share
Tuấn AnhNguyễn @anhnguyen1494
Aug 28th, 2018 10:41 AM

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

+1
| Reply
Share
Tran Duc Thang @thangtd90
Aug 29th, 2018 1:19 AM

@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 🤔

+1
| Reply
Share
Tuấn AnhNguyễn @anhnguyen1494
Aug 29th, 2018 1:41 AM

@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 😂

+1
| Reply
Share
Tran Duc Thang @thangtd90
Aug 29th, 2018 1:44 AM
+1
| Reply
Share