Commit efb3dcdc authored by Nicolas Joyard's avatar Nicolas Joyard

Change score calculation to exponential decay

parent bf3d5b31
[{
"model": "memopol_settings.setting",
"pk": "SCORE_DECAY_NUM",
"fields": {
"value": "0",
"comment": "Numerator for decay rate in score formula. Set to 0 for no decay, 1 otherwise. Score formula is base_score * exp( -(vote_age*DECAY_NUM/DECAY_DENOM)^(2*EXPONENT) )."
}
},
{
"model": "memopol_settings.setting",
"pk": "SCORE_DECAY_DENOM",
"fields": {
"value": "1",
"comment": "Denominator for decay rate in score formula. Must be nonzero. Set to higher value to delay the score decay. Score formula is base_score * exp( -(vote_age*DECAY_NUM/DECAY_DENOM)^(2*EXPONENT) )."
}
},{
"model": "memopol_settings.setting",
"pk": "SCORE_EXPONENT",
"fields": {
"value": "1",
"comment": "Exponent for score formula. Set to higher value for a steeper decay around the cutoff. Score formula is base_score * exp( -(vote_age*DECAY_NUM/DECAY_DENOM)^(2*EXPONENT) )."
}
},{
"model": "memopol_settings.setting",
"pk": "SCORE_DECIMALS",
"fields": {
"value": "0",
"comment": "Number of score decimals to display. Use 0 for integers."
}
}]
\ No newline at end of file
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
from django.core import serializers
from django.db import migrations
fixture_dir = os.path.abspath(
os.path.join(
os.path.dirname(__file__),
'../fixtures'))
fixture_filename = 'score_settings.json'
def load_fixture(apps, schema_editor):
fixture_file = os.path.join(fixture_dir, fixture_filename)
fixture = open(fixture_file, 'rb')
objects = serializers.deserialize('json', fixture, ignorenonexistent=True)
for obj in objects:
obj.save()
fixture.close()
class Migration(migrations.Migration):
dependencies = [
('memopol_settings', '0001_initial'),
]
operations = [
migrations.RunPython(load_fixture),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('representatives_recommendations', '0005_representativescore'),
]
operations = [
migrations.RunSQL(
"""
DROP VIEW "representatives_recommendations_votescores" CASCADE;
"""
),
migrations.AlterField(
model_name='recommendation',
name='weight',
field=models.FloatField(default=0),
),
migrations.RunSQL(
"""
CREATE VIEW "representatives_recommendations_votescores"
AS SELECT
representatives_votes_vote.id,
representatives_votes_vote."position",
representatives_votes_vote.proposal_id,
representatives_votes_vote.representative_id,
ROUND(CAST(EXP(-((decay_num.value * EXTRACT(days FROM CURRENT_DATE - representatives_votes_proposal.datetime) / decay_denom.value) ^ (2 * exponent.value)))
* (CASE
WHEN representatives_votes_vote."position"::text = representatives_recommendations_recommendation.recommendation::text THEN representatives_recommendations_recommendation.weight
ELSE 0 - representatives_recommendations_recommendation.weight
END) AS NUMERIC), decimals.value) AS score
FROM representatives_votes_vote
JOIN (SELECT CAST(TO_NUMBER(value, '99999') AS FLOAT) AS value FROM memopol_settings_setting WHERE key = 'SCORE_DECAY_NUM') decay_num ON 1=1
JOIN (SELECT CAST(TO_NUMBER(value, '99999') AS FLOAT) AS value FROM memopol_settings_setting WHERE key = 'SCORE_DECAY_DENOM') decay_denom ON 1=1
JOIN (SELECT CAST(TO_NUMBER(value, '99999') AS FLOAT) AS value FROM memopol_settings_setting WHERE key = 'SCORE_EXPONENT') exponent ON 1=1
JOIN (SELECT CAST(TO_NUMBER(value, '99999') AS INTEGER) AS value FROM memopol_settings_setting WHERE key = 'SCORE_DECIMALS') decimals ON 1=1
JOIN representatives_votes_proposal ON representatives_votes_vote.proposal_id = representatives_votes_proposal.id
LEFT JOIN representatives_recommendations_recommendation ON representatives_votes_proposal.id = representatives_recommendations_recommendation.proposal_id
WHERE representatives_recommendations_recommendation.id IS NOT NULL;
"""
),
migrations.RunSQL(
"""
CREATE VIEW "representatives_recommendations_dossierscores"
AS SELECT
"representatives_recommendations_votescores"."representative_id" || ':' || "representatives_votes_proposal"."dossier_id" AS "id",
"representatives_recommendations_votescores"."representative_id",
"representatives_votes_proposal"."dossier_id",
SUM("representatives_recommendations_votescores"."score") AS "score"
FROM "representatives_recommendations_votescores"
INNER JOIN "representatives_votes_proposal"
ON ( "representatives_recommendations_votescores"."proposal_id" = "representatives_votes_proposal"."id" )
GROUP BY
"representatives_recommendations_votescores"."representative_id",
"representatives_votes_proposal"."dossier_id"
"""
),
migrations.RunSQL(
"""
CREATE VIEW "representatives_recommendations_representativescore"
AS SELECT
"representatives_representative"."id" as "representative_id",
COALESCE(SUM("representatives_recommendations_votescores"."score"), 0) AS "score"
FROM
"representatives_representative"
LEFT OUTER JOIN "representatives_recommendations_votescores"
ON "representatives_recommendations_votescores"."representative_id" = "representatives_representative"."id"
GROUP BY "representatives_representative"."id"
"""
)
]
......@@ -12,7 +12,7 @@ class DossierScore(models.Model):
representative = models.ForeignKey(Representative,
on_delete=models.DO_NOTHING)
dossier = models.ForeignKey(Dossier, on_delete=models.DO_NOTHING)
score = models.IntegerField(default=0)
score = models.FloatField(default=0)
class Meta:
managed = False
......@@ -25,7 +25,7 @@ class VoteScore(models.Model):
representative = models.ForeignKey(
Representative, related_name='votescores', null=True)
position = models.CharField(max_length=10)
score = models.IntegerField(default=0)
score = models.FloatField(default=0)
class Meta:
managed = False
......@@ -36,7 +36,7 @@ class VoteScore(models.Model):
class RepresentativeScore(models.Model):
representative = models.OneToOneField('representatives.representative',
primary_key=True, related_name='score')
score = models.IntegerField(default=0)
score = models.FloatField(default=0)
class Meta:
managed = False
......@@ -52,7 +52,7 @@ class Recommendation(models.Model):
recommendation = models.CharField(max_length=10, choices=Vote.VOTECHOICES)
title = models.CharField(max_length=1000, blank=True)
description = models.TextField(blank=True)
weight = models.IntegerField(default=0)
weight = models.FloatField(default=0)
class Meta:
ordering = ['proposal__datetime']
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment