繁体   English   中英

如何找到最接近的匹配数组

[英]How to find the closest matching array

家具店网站的客户可以将 select 产品添加到“样式书”中。 每个产品都属于一种“风格”。 家具店有一些造型师,每个人都制作了自己的风格书,代表了他们的风格和专业知识。 我希望能够找到最符合客户风格手册的造型师。 对于每本风格书,我都会计算每种风格的产品数量。

$stylists = [
    'Nanda'     => [
        'Design'  => 20,
        'Retro'   => 0,
        'Rustiek' => 0,
    ],
    'Angelique' => [
        'Design'  => 0,
        'Retro'   => 20,
        'Rustiek' => 0,
    ],
    'Lissy'     => [
        'Design'  => 10,
        'Retro'   => 10,
        'Rustiek' => 0,
    ],
];

客户的风格书也是如此:

$customer = [
    'Design'  => 15,
    'Retro'   => 10,
    'Rustiek' => 0,
];

在这种情况下,Lissy 应该是最佳匹配。

产品的数量并不重要,因为这取决于造型师的活跃程度。 更重要的是造型师匹配了大部分客户的styles。 例如:

'Stylist'     => [
    'Design'  => 10,
    'Retro'   => 10,
    'Rustiek' => 0,
]

应该仍然是一个更好的匹配比

'Stylist'     => [
    'Design'  => 300,
    'Retro'   => 0,
    'Rustiek' => 180,
]

我已经尝试根据客户风格书的重要性顺序为造型师的风格书评分和百分比,但我仍然没有得到 100% 的最佳匹配。 谷歌也没有让我到任何地方。

正如我们已经讨论过的,您的 model 的问题在于,它依赖于产品的数量。 但我们需要的是造型师使用的风格的指标。 换句话说,我们消除了计数并用相对加权的指标(在这种情况下为百分比)替换它。 例如,具有以下产品组合的造型师:

[
    style1 => 30,
    style2 => 10,
    style3 => 5
]

产品数量为45 = 30 + 10 + 5这将产生如下样式配置文件:

[
    style1 => 0.66,
    style2 => 0.22,
    style3 => 0.11
]

要将 stylist-style-profile 与 client-style-profile 匹配,我们需要对 client-stylebook [15, 10, 0]做同样的事情:

[
    style1 => 0.60
    style2 => 0.40
    style3 => 0.00
]

这背后的想法是,我们评估造型师如何受到某种风格的影响,并且对于我们想要找到最合适的造型师的产品,结果可能非常相似。

如果造型师制作的产品风格不是我们真正需要的搭配,我们会使用加权相对系数(例如 0.11)对这一事实进行评分。 这并不重要,但我们仍然承认设计可能有些偏颇这一事实。

因此,如果造型师有很多我们想要的具有某种风格的产品,它不会改变结果。

请让我知道,如果这有帮助,如果你想改变什么。 从这里我们还可以实施其他选项和规则。

您可以在下面找到我的 RatingModel。

<?php

class RatingModel {
    private $name;
    private $preferences;
    private $preferencesWeighted;

    public function RatingModel($name, array $preferences) {
        $this->name = $name;
        $this->preferences = $preferences;
        $this->init();
    }

    private function init() {
        $total = 0;
        foreach ($this->preferences as $value) {
            $total += $value;
        }
        if ($total > 0) {
            foreach ($this->preferences as $value) {
                $this->preferencesWeighted[] = $value / $total;
            }
        } else {
            $this->preferencesWeighted = array_fill(0, sizeof($this->preferences), 0);
        }
    }

    public function getName() {
        return $this->name;
    }

    public function getPreferences() {
        return $this->preferences;
    }

    public function getPreferencesWeighted() {
        return $this->preferencesWeighted;
    }

    public function distanceToModel($ratingModel) {
        $delta = [];
        for ($i = 0; $i < sizeof($this->preferencesWeighted); $i++) {
            $delta[] = abs($this->preferencesWeighted[$i] - $ratingModel->getPreferencesWeighted()[$i]);
        }
        return $delta;
    }

    public function scoreToModel($ratingModel) {
        $distanceToModel = $this->distanceToModel($ratingModel);
        $score = [];
        foreach ($distanceToModel as $value) {
            $score[] = $value * $value;
        }
        return sqrt(array_sum($score));
    }
}

$customer = new RatingModel('Customer', [15, 10, 0]);
$nanda = new RatingModel('Nanda', [20, 0, 0]);
$angelique = new RatingModel('Angelique', [0, 20, 0]);
$lissy = new RatingModel('Lissy', [10, 0, 0]);
$mary = new RatingModel('Mary', [0, 0, 0]);
$max = new RatingModel('Max', [12, 0, 5]);
$simon = new RatingModel('Simon', [17, 2, 5]);
$manuel = new RatingModel('Manuel', [17, 8, 10]);
$betty = new RatingModel('Betty', [16, 9, 5]);
$sally = new RatingModel('Sally', [15, 10, 4]);
$peter = new RatingModel('Peter', [16, 9, 1]);

$stylists = [$nanda, $angelique, $lissy, $mary, $max, $simon, $manuel, $betty, $peter, $sally];

$relativeToClient = [];
foreach ($stylists as $stylist) {
    $relativeToClient[] = [
        'stylist' => $stylist->getName(),
        'distance' => $stylist->distanceToModel($customer),
        'score' => $stylist->scoreToModel($customer)
    ];
}

echo '<pre>';
print_r($stylists);
echo '<hr>';
print_r($customer);
echo '<hr>';
print_r($relativeToClient);
echo '<hr>from best fit to worst (low score means low delta)<hr>';
$results = array_column($relativeToClient, 'score', 'stylist');
asort($results);
print_r($results);
echo '</pre>';

右下方是结果(较低的值更好):

Array
(
    [Peter] => 0.067936622048676
    [Sally] => 0.1700528000819
    [Betty] => 0.20548046676563
    [Manuel] => 0.35225222874108
    [Simon] => 0.3942292057505
    [Max] => 0.50765762377392
    [Nanda] => 0.56568542494924
    [Lissy] => 0.56568542494924
    [Mary] => 0.7211102550928
    [Angelique] => 0.84852813742386
)

如果我们看一下我们注意到的两位最合适的造型师,Peter 胜过 Sally,因为 Sally 有更多不同风格的产品。

Sally: [15, 10, 4]
Peter: [16, 9, 1]

您可能还注意到,Nanda 和 Lissy 的得分相同:

Nanda: [20, 0, 0]
Lissy: [10, 0, 0]

// relatively, for both => [1.00, 0.00, 0.00]

他们都被认为同样合适。 Nanda 多出 5 种产品,而 Lissy 少了 5 种产品的第一种风格,但这没关系,因为它们都只提供一种风格,重要的是:他们离理想的客户风格有多远。

您还可以实现逻辑,这样您就没有偏差因素,并且在比较时更加严格。 在这种情况下,您可能希望排除一些参数。

例如,仅比较[15, 10][16, 9] - 在这种情况下,Sally 实际上会获胜,因为在偏好方面她与客户没有差异:

莎莉:

[
    style1 => 0.60,
    style2 => 0.40
]

彼得:

[
    style1 => 0.64,
    style2 => 0.36
]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM