Skip to content
Advertisement

I can’t get my additive weighting algorithm to work properly

I have a data structure that look like this

$data = [
    [
        "name" => "user_a",
        "code" => "c1",
        "description" => "criteria 1",
        "type" => "benefit",
        "weight" => 25,
        "value" => 75
    ],
    [
        "name" => "user_a",
        "code" => "c2",
        "description" => "criteria 2",
        "type" => "benefit",
        "weight" => 20,
        "value" => 67
    ],
    [
        "name" => "user_a",
        "code" => "c3",
        "description" => "criteria 3",
        "type" => "benefit",
        "weight" => 15,
        "value" => 80
    ],
    [
        "name" => "user_a",
        "code" => "c4",
        "description" => "criteria 4",
        "type" => "benefit",
        "weight" => 22,
        "value" => 90
    ],
    [
        "name" => "user_a",
        "code" => "c5",
        "description" => "criteria 5",
        "type" => "benefit",
        "weight" => 8,
        "value" => 20
    ],
    [
        "name" => "user_a",
        "code" => "c6",
        "description" => "criteria 6",
        "type" => "benefit",
        "weight" => 10,
        "value" => 80
    ],
    [
        "name" => "user_b",
        "code" => "c1",
        "description" => "criteria 1",
        "type" => "benefit",
        "weight" => 25,
        "value" => 65
    ],
    [
        "name" => "user_b",
        "code" => "c2",
        "description" => "criteria 2",
        "type" => "benefit",
        "weight" => 20,
        "value" => 70
    ],
    [
        "name" => "user_b",
        "code" => "c3",
        "description" => "criteria 3",
        "type" => "benefit",
        "weight" => 15,
        "value" => 80
    ],
    [
        "name" => "user_b",
        "code" => "c4",
        "description" => "criteria 4",
        "type" => "benefit",
        "weight" => 22,
        "value" => 90
    ],
    [
        "name" => "user_b",
        "code" => "c5",
        "description" => "criteria 5",
        "type" => "benefit",
        "weight" => 8,
        "value" => 20
    ],
    [
        "name" => "user_b",
        "code" => "c6",
        "description" => "criteria 6",
        "type" => "benefit",
        "weight" => 10,
        "value" => 80
    ],
];

I’m trying to get the normalized values but it wasn’t giving me the expected result with my current algorithm.

// This one is fine
$matrix_x = get_matrix_x($data);

// result: [
//   "user_a": [75, 67, 80, 90, 20, 80],
//   "user_b": [65, 70, 80, 90, 20, 80],
//   "user_c": [56, 70, 75, 80, 50, 70],
// ];


// This one is producing the wrong result (I rounded it just to make it readable, decimals are OK to be shown as is)
$matrix_r = get_matrix_r($data, $matrix_x);

// current result: [
//   "user_a": [0.8, 0.7, 0.8, 1.0, 0.2, 0.8],
//   "user_b": [0.7, 0.7, 0.8, 1.0, 0.2, 0.8],
//   "user_c": [0.7, 0.8, 0.9, 1.0, 0.6, 0.8],
// ];

// expected result: [
//   "user_a": [1.0, 0.9, 1.0, 1.0, 0.4, 1.0],
//   "user_b": [0.8, 1.0, 1.0, 1.0, 0.4, 1.0],
//   "user_c": [0.7, 1.0, 0.9, 0.8, 1.0, 0.8],
// ];

I have been stuck with this problem for about 4 days, the problem is in the min(...) and max(...) function inside the get_matrix_r method. It was supposed to take the number from top to bottom for each column instead of taking the highest/lowest number directly from the key given by $matrix_x but I don’t know how to do that.

I also asked a question related to this issue, but when I loop inside the $reducer using the given solutions, it produce extra items in the result. Please help!

functions.php

/**
 * Generate matrix_x from the given data.
 * 
 * @param  array $data
 * @param  string $key
 * @param  string $valkey
 * @return array
 */
function get_matrix_x(array $data, string $key = 'name', string $valkey = 'value')
{
    $reducer = function ($acc, $item) use ($key, $valkey) {
        $index = $item[$key];

        if (!isset($acc[$index])) {
            $acc[$index] = [];
        }

        $acc[$index][] = (int) $item[$valkey];

        return $acc;
    };

    return array_reduce($data, $reducer, []);
}

/**
 * Generate matrix_r from data and matrix_x as origin.
 * 
 * @param  array $data
 * @param  array $origin
 * @param  string $key
 * @param  string $valkey
 * @param  string $compkey
 * @return array
 */
function get_matrix_r(array $data, array $origin, string $key = 'name', string $valkey = 'value', string $compkey = 'type')
{
    $reducer = function ($acc, $item) use ($key, $valkey, $origin, $compkey) {
        $index = $item[$key];

        if (!isset($acc[$index])) {
            $acc[$index] = [];
        }

        $item[$compkey] === 'cost'
            ? $acc[$index][] = (int) $item[$valkey] / min($origin[$index])
            : $acc[$index][] = (int) $item[$valkey] / max($origin[$index]);

        return $acc;
    };

    return array_reduce($data, $reducer, []);
}

Advertisement

Answer

Well, the first problem, is that in the dataset you are providing there is not user_c, but in the output matrix there are references to that, so that’s weird.

The second problem, is that in the reducer, you are considering the ROWs, and not the COLUMNs… to consider those, you should do something like this:

/**
 * Generate matrix_r from data and matrix_x as origin.
 * 
 * @param  array $data
 * @param  array $origin
 * @param  string $key
 * @param  string $valkey
 * @param  string $compkey
 * @return array
 */
function get_matrix_r(array $data, array $origin, string $key = 'name', string $valkey = 'value', string $compkey = 'type')
{
     $reducer = function ($acc, $item) use ($key, $valkey, $origin, $compkey) {
          $index = $item[$key];
          print_r($item);
          if (!isset($acc[$index])) {
               $acc[$index] = [];
          }
          // consider the nth COLUMN, with $origin[$index] you was considering the ROW
          $col = array_column($origin, count($acc[$index])); 
          $item[$compkey] === 'cost'
               ? $acc[$index][] = (int) $item[$valkey] / min($col)
               : $acc[$index][] = (int) $item[$valkey] / max($col);

          return $acc;
     };

     return array_reduce($data, $reducer, []);
}
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement