python - 从 MySQL 数据计算加权分数的函数?

标签 python mysql algorithm math probability

我有两个表(主题和术语),第三个表表示两个实体之间的多对多关系。

每个关系(称为装袋)都有一个源(文本)和一个权重(0 到 100 之间的整数)。同一对(topic-term)可以有多个 bagging(不同来源),每个都有不同的权重。

现在,当我查询一个主题以找出它的最佳术语(更多权重)时,理想情况下我想要具有计算权重的唯一值:

  • 权重为 100 表示该项目处于最大值
  • 同一对(不同来源)的多个重量比单对重
  • 没有“负”重量

这是数据库模式:

| TOPIC
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| label | varchar(255)     | NO   | UNI | NULL    |                |
| wtext | varchar(40)      | YES  |     | NULL    |                |
+-------+------------------+------+-----+---------+----------------+

| TERM
+-------+---------------------+------+-----+---------+----------------+
| Field | Type                | Null | Key | Default | Extra          |
+-------+---------------------+------+-----+---------+----------------+
| id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| label | varchar(255)        | NO   | UNI | NULL    |                |
| slug  | varchar(255)        | NO   |     | NULL    |                |
+-------+---------------------+------+-----+---------+----------------+

| BAGGING
+----------+---------------------+------+-----+---------+----------------+
| Field    | Type                | Null | Key | Default | Extra          |
+----------+---------------------+------+-----+---------+----------------+
| id       | int(10) unsigned    | NO   | PRI | NULL    | auto_increment |
| topic_id | int(11) unsigned    | NO   | MUL | NULL    |                |
| term_id  | bigint(11) unsigned | NO   | MUL | NULL    |                |
| weight   | tinyint(1) unsigned | NO   |     | NULL    |                |
| source   | varchar(8)          | YES  |     | GEN     |                |
+----------+---------------------+------+-----+---------+----------------+

这是我的简单查询:

SELECT 
    bagging.topic_id as topic_id,
    topic.label as topic_label,
    bagging.term_id as term_id,
    term.label as term_label,
    bagging.weight as weight,
    bagging.source as source
FROM
    bagging
JOIN term   ON term.id  = bagging.term_id
JOIN topic  ON topic.id = bagging.topic_id
WHERE
    bagging.topic_id = ( SELECT id FROM topic WHERE label = 'Altruism' )
ORDER BY
    bagging.weight DESC

这给了我以下结果:

+----------+-------------+---------+-----------------------+--------+--------+
| topic_id | topic_label | term_id | term_label            | weight | source |
+----------+-------------+---------+-----------------------+--------+--------+
|        8 | Altruism    |      83 | Altruism              |    100 | TOPIC  |
+----------+-------------+---------+-----------------------+--------+--------+
|        8 | Altruism    |     100 | Altruism (philosophy) |     95 | WPRD   |
|        8 | Altruism    |     100 | Altruism (philosophy) |     95 | MAN    |
|        8 | Altruism    |      84 | Truist                |     95 | MAN    |
|        8 | Altruism    |      84 | Truist                |     15 | WPRD   |
+----------+-------------+---------+-----------------------+--------+--------+
|        8 | Altruism    |      94 | Selfless action       |     95 | WPRD   |
|        8 | Altruism    |      95 | Alturism              |     95 | WPRD   |
|        8 | Altruism    |      96 | Digital altruism      |     95 | WPRD   |
|        8 | Altruism    |      97 | Selflessly            |     95 | WPRD   |
|        8 | Altruism    |      98 | Altruistical          |     95 | WPRD   |
|        8 | Altruism    |      99 | Law of mutual aid     |     95 | WPRD   |
|        8 | Altruism    |     101 | Altruistically        |     95 | WPRD   |
|        8 | Altruism    |      85 | Altruistic            |     95 | WPRD   |
|        8 | Altruism    |      86 | Altruist              |     95 | WPRD   |
|        8 | Altruism    |      87 | Otherism              |     95 | WPRD   |
|        8 | Altruism    |      88 | Unselfishness         |     95 | WPRD   |
|        8 | Altruism    |      89 | Altruistic behavior   |     95 | WPRD   |
|        8 | Altruism    |      90 | Altutrists            |     95 | WPRD   |
|        8 | Altruism    |      91 | Altruists             |     95 | WPRD   |
|        8 | Altruism    |     102 | Pathological altruism |     95 | WPRD   |
+----------+-------------+---------+-----------------------+--------+--------+

现在,如何为这个特定示例创建一个考虑以下因素的评分函数:

  • 利他主义无敌,只能等同(=100)
  • Truist 显然应该受到 15/100 权重的惩罚,但也应该考虑到有两个权重的事实,尤其是因为第二个是 95
  • 利他主义(哲学) 应该比其他所有人都重要(利他主义 除外,只能等同。)即使 95 的两倍看起来比 100 大。<

最终结果不必从 1 缩放到 100,它可以是考虑到这些限制的相对或抽象评级。

我尝试为每一行计算 ( term_sum_weight * 100/topic_weight_sum_of_all_terms ) 但看到下面的结果,它们的权重不够。

Results computed on spreadsheets to try. 例如,如何为 95 到 96 赋予比 1 到 20 更大的权重?

公式比将要使用的语言更重要......在我的程序中使用 MySQL 或 Python/PHP。

预期结果(沿着这些线...)

+----------+-------------+---------+-----------------------+-------+--------+
| topic_id | topic_label | term_id | term_label            | score | source |
+----------+-------------+---------+-----------------------+-------+--------+
|        8 | Altruism    |      83 | Altruism              |     1 | TOPIC  |
+----------+-------------+---------+-----------------------+-------+--------+
|        8 | Altruism    |     100 | Altruism (philosophy) |  0.98 | WPRD   |
|        8 | Altruism    |      84 | Truist                |  0.96 | MAN    |
+----------+-------------+---------+-----------------------+--------+-------+
|        8 | Altruism    |      94 | Selfless action       |  0.95 | MAN    |
|        8 | Altruism    |      95 | Alturism              |  0.95 | MAN    |
|        8 | Altruism    |      96 | Digital altruism      |  0.95 | MAN    |
                                ...........
|        8 | Altruism    |      97 | Selflessly            |  0.95 | MAN    |
|        8 | Altruism    |      90 | Altutrists            |  0.95 | MAN    |
|        8 | Altruism    |      91 | Altruists             |  0.95 | MAN    |
|        8 | Altruism    |     102 | Pathological altruism |  0.95 | MAN    |
+----------+-------------+---------+-----------------------+--------+-------+

最佳答案

您应该首先计算出您所需的公式应具有的一些属性。一些可能的假设可能如下:

  1. 重量为 100 的 bagging 总能得到最高分(无论是 1 还是 100)
  2. 添加一个权重为零的装袋不会改变任何事情
  3. 添加非零权重的装袋会增加对的分数,除非分数已经达到最大值
  4. 如果两对各有一个 bagging,则权重越大得分越高

条件 2 和 3 表明类似加法。但是条件 1 告诉你,你不能只添加,因为这样做会超过分数。一种查看方式是使用物理类比。把你的重量想象成速度。在日常生活中,您可以简单地增加速度。但是在非常高的速度下,狭义相对论告诉我们,我们永远无法超过光速的极限。添加两个低于光速的速度确实会导致速度高于但仍低于光速。在您的设置中,“光速”是最大权重 100。

所以查找the formula for the addition of speeds并使其适应您的用例。如果你有两个重量 vw 的装袋,那么总重量将是

(v + w)/(1 + v*w/10000)

现在您需要计算出一个公式,在单个公式中对任意数量的被加数执行上述操作,或者您编写一些应用程序代码以增量计算累加器与数据库中下一项之间的总和。或者您继续阅读维基百科,发现以下等式成立:

c-s   c-v   c-w
--- = --- * ---
c+s   c+v   c+w

这里的 s 是速度的总和,或者是你的世界中的分数。但是 s 越大,这个分数就会越小。因此,您可以按 (c-s)/(c 排序,而不是按降序排序 s +s) 升序排列。不幸的是 MySQL doesn't have a PRODUCT aggregate function .但是您可以使用对数将乘积转换为总和:

SUM(LOG((100-weight)/(100+weight))) AS score

不幸的是,MySQL 不像 IEEE 浮点运算那样处理无穷大(即 log(0) = -∞),而是将 100 的权重转换为 的分数空。因此,您可以使用 SORT BY (score IS NULL) DESC 或类似方法将 NULL 分数排在非 NULL 分数之前。或者您以正确处理零的方式将上面的值转换回值 s

SELECT …,
  IF(MAX(weight) = 100, 1,
    (1-EXP(SUM(LOG((100-weight)/(100+weight)))))/
    (1+EXP(SUM(LOG((100-weight)/(100+weight)))))) AS score

在这里,您可以将 EXP(SUM(LOG(…))) 视为 PRODUCT(…)。要为 s 求解 (c-s)/(c+s)=p(p 作为我刚才提到的乘积),您需要计算s=c*(1-p)/(1+p)。因此,通过省略 c*,您可以获得 0 到 1 范围内的分数,而不是 0 到 100,这与您到目前为止的计算类似。 MAX(weight) = 100 情况会导致 LOG(0) 使整个计算为 NULL,因此必须是单独处理。

参见 http://sqlfiddle.com/#!9/1cd56/1例如使用您的数据。利他主义返回 1,利他主义(哲学)返回 0.9987,真理主义返回 0.9628,其他返回 0.95。第二个分数比您在问题中的预期要大得多,但我没有一个好主意来调整公式以使其更像您的预期。

关于python - 从 MySQL 数据计算加权分数的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41423225/

相关文章:

Python3.4 : OSError: [Errno 12] Cannot allocate memory

python - 如何通过flask消息显示html内容?

MySQL 用第一个表中的数据填充第二个表

algorithm - 银行柜员再分级模拟

algorithm - 如何在 C++ 中将函数作为参数传递给类构造函数

regex - 2 模式字符串匹配算法

python - 聚合 pandas 数据框和字符串条目

javascript - 注销后禁用浏览器 'Back' 按钮?

php - 在 000webhost 上使用 laravel 时 MySQL 连接被拒绝

mysql - Delphi 和 Web 应用程序之间的行尾问题