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

3

一家家具店的网站上,顾客可以选择产品并将其添加到“风格手册”中。每个产品都属于一个“风格”。 该家具店有一些造型师,他们各自制作了代表自己风格和专业知识的风格手册。 我想要能够找到最符合顾客风格手册的造型师。 对于每个风格手册,我有每种风格产品数量的计数。

$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应该是最合适的选择。产品数量并不重要,因为这取决于造型师的活跃程度。更重要的是,造型师能够与客户的大多数风格相匹配。例如:
'Stylist'     => [
    'Design'  => 10,
    'Retro'   => 10,
    'Rustiek' => 0,
]

应该仍然比之前更匹配

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

我尝试根据客户的风格指南重要性的顺序,给造型师的风格指南打分和百分比,但仍然不能100%地找到最佳匹配。

Google也没有给我答案。


1
如果有一个名叫 Chantal 的设计师,其得分如下:'Design' => '10''Retro' => '15''Rustiek' => '0',那么相较于 Lissy,更高的 'Retro' 得分是否使 Chantal 更适合客户?虽然两者在“匹配客户风格”的数量上得分相等,但 Chantal 在其中一项匹配上得分更高。 - jibsteroos
@jibsteroos为什么?最优情况下它将是相等的-只有5个差距-权重是相同的(据他所述)。但这是一个有效的观点。我的意思是,如果你想要更多的精度,那么你需要不同的权重,否则你就会有多个“赢家”。 - F. Müller
@jibsteroos @ F.Müller 我不想依赖计数,因为如果一个造型师的计数非常高,它可能会导致她始终是最佳匹配。它可以用来确定两个相等的匹配中的胜者,但我不介意随机选择其中之一。 - Gydo Makkinga
@ChrisvanderGeld 他在帖子中写了那个。客户也有一个样式手册。是的,我们正谈论着那个。 :) - F. Müller
@F.Müller 嗯,看起来我没有理解你的解释。 如果客户有9、3、7。 我怎么才能找到正确的发型师? 你几乎无法开始数数,因为你不知道何时停止或转到第二个数字。从Gydo的评论中看到的问题,它与Nanda相匹配,而不是Lissy。他如何确定风格的重要性?这种计算似乎完全忽略了风格的重要性,只是将最大的数字与其他大数字相匹配。 - Chris van der Geld
显示剩余10条评论
1个回答

5

正如我们已经讨论过的,你的模型存在问题,它依赖于产品数量。但是我们需要的是造型师正在使用的风格指标。换句话说,我们消除了计数,并用相对加权的指标替换它(在本例中是百分比)。例如,一个发型师有以下产品组合:

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

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

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

为了将造型师的造型档案与客户的样式档案相匹配,我们需要对客户的风格手册 [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]

他们两个都被认为是同样适合的。南达比莉西多5件第一款产品,而莉西比南达少5件第一款产品,但这并不重要,因为他们两个只提供一种款式,这才是重要的:他们与理想状态(即客户的风格)相差多远。
你也可以实现逻辑,使其没有偏见因素,并在比较方面更加严格。在这种情况下,您可能希望排除某些参数。
例如,仅比较[15, 10][16, 9] - 在这种情况下,莎莉实际上会获胜,因为当涉及到喜好时,她与客户没有差距:
莎莉:
[
    style1 => 0.60,
    style2 => 0.40
]

Peter:

[
    style1 => 0.64,
    style2 => 0.36
]

谢谢@F.Müller!这太棒了!你的大部分解决方案是我已经做过的,除了计算距离。这排除了计数,使得内容较少的造型师仍然可以匹配。这正是我所需要的! - Gydo Makkinga
@GydoMakkinga 我很高兴我能帮到你。 :) - F. Müller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接