Revised score calculation

master
Rafael 2024-06-24 04:25:23 +02:00
parent ba37ca72f8
commit b5aa8d93fb
1 changed files with 92 additions and 79 deletions

View File

@ -1,6 +1,6 @@
import 'dart:math'; import 'dart:math';
import 'package:flutter/foundation.dart' show kDebugMode, debugPrint;
import '../enumerations.dart'; import '../enumerations.dart';
import '../models/language.dart';
import '../models/user_profile.dart'; import '../models/user_profile.dart';
/// Approximate determination of age /// Approximate determination of age
@ -95,96 +95,102 @@ double shortestDistanceBetweenUsers(
/// Calculates the matching score of [otherUser] for [currentUser]. /// Calculates the matching score of [otherUser] for [currentUser].
double calculateMatchScore(UserProfile currentUser, UserProfile otherUser) { double calculateMatchScore(UserProfile currentUser, UserProfile otherUser) {
// weights
const double distanceWeight = 0.55;
const double skillWeight = 0.25;
const double availabilityWeight = 0.065;
const double visionWeight = 0.04;
const double riskWeight = 0.035;
const double workWeight = 0.025;
const double cultureWeight = 0.02;
const double communicationWeight = 0.015;
if (kDebugMode) {
double weightSum = (distanceWeight +
skillWeight +
availabilityWeight +
visionWeight +
riskWeight +
workWeight +
cultureWeight +
communicationWeight);
if (weightSum != 1) {
debugPrint(
'DEBUG Info --> calculateMatchScore : Weights Sum $weightSum != 1');
}
}
// Score on locations distance // Score on locations distance
double distance = shortestDistanceBetweenUsers(currentUser, otherUser); double distance = shortestDistanceBetweenUsers(currentUser, otherUser);
double distanceScore = _distanceToPercentage(distance); double distanceScore = _distanceToPoints(distance);
// Score on common languages
List<Language> currentLang = currentUser.languages;
List<Language> otherLang = otherUser.languages;
int matchingLanguages =
currentLang.toSet().intersection(otherLang.toSet()).length;
int langScore = 0;
if (matchingLanguages >= 3) {
langScore = 10;
} else if (matchingLanguages == 2) {
langScore = 9;
} else if (matchingLanguages == 1) {
langScore = 8;
}
// Score on common Sectors
List<SectorOption> currentSectors = currentUser.sectors;
List<SectorOption> otherSectors = otherUser.sectors;
int matchingSectors =
currentSectors.toSet().intersection(otherSectors.toSet()).length;
int sectorScore = 0;
if (matchingSectors >= 4) {
sectorScore = 10;
} else if (matchingSectors == 3) {
sectorScore = 9;
} else if (matchingSectors == 2) {
sectorScore = 7;
} else if (matchingSectors == 1) {
sectorScore = 5;
}
// Score on skills // Score on skills
int matchingSkillsSought = currentUser.skillsSought int matchingSkillsSought = currentUser.skillsSought
.toSet() .toSet()
.intersection(otherUser.skills.toSet()) .intersection(otherUser.skills.toSet())
.length; .length;
int matchingSkillsOffered = otherUser.skills int matchingSkillsOffered = currentUser.skills
.toSet() .toSet()
.intersection(currentUser.skillsSought.toSet()) .intersection(otherUser.skillsSought.toSet())
.length; .length;
int skillsSought = currentUser.skillsSought.length;
int skillsOffered = otherUser.skills.length; int skillsOffered = otherUser.skills.length;
// Idea: Calculate sum of matching skills divided by amount of skills listed. int scoreSought = 0;
// As each list can have up to 3 skills max, this gives the following equation if (matchingSkillsSought >= 3) {
// with 3 skills: 0 1/3 2/3 3/3; with 2 skills: 0 1/2 2/2; with 1 skill: 0 1. scoreSought = 15;
// In total this will result in a total of 5 different states: } else if (matchingSkillsSought == 2) {
// [0], [1/3], [1/2], [2/3], and [1]. scoreSought = 12;
} else if (matchingSkillsSought == 1) {
double valueSought = matchingSkillsSought / skillsSought; scoreSought = 9;
int scoreSought;
if (valueSought == 1) {
scoreSought = 4;
} else if (valueSought == 2 / 3) {
scoreSought = 3;
} else if (valueSought == 1 / 2) {
scoreSought = 2;
} else if (valueSought == 1 / 3) {
scoreSought = 1;
} else {
scoreSought = 0;
} }
double valueOffered = matchingSkillsOffered / skillsOffered; double valueOffered = matchingSkillsOffered / skillsOffered;
int scoreOffered; int scoreOffered;
if (valueOffered == 1) { if (valueOffered == 1) {
scoreOffered = 4; scoreOffered = 15;
} else if (valueOffered == 4 / 5) {
scoreOffered = 14;
} else if (valueOffered == 3 / 4) {
scoreOffered = 13;
} else if (valueOffered == 2 / 3) { } else if (valueOffered == 2 / 3) {
scoreOffered = 3; scoreOffered = 12;
} else if (valueOffered == 3 / 5) {
scoreOffered = 11;
} else if (valueOffered == 1 / 2) { } else if (valueOffered == 1 / 2) {
scoreOffered = 2; scoreOffered = 10;
} else if (valueOffered == 2 / 5) {
scoreOffered = 9;
} else if (valueOffered == 1 / 3) { } else if (valueOffered == 1 / 3) {
scoreOffered = 1; scoreOffered = 8;
} else if (valueOffered == 1 / 4) {
scoreOffered = 7;
} else if (valueOffered == 1 / 5) {
scoreOffered = 6;
} else { } else {
scoreOffered = 0; scoreOffered = 0;
} }
int skillsScore = scoreSought + scoreOffered; // 8 points max double skillsScore = (scoreSought + scoreOffered) / 1.5;
// Score on availability // Score on availability
int availabilityScore; int availabilityScore;
AvailabilityOption currentAvail = currentUser.availability; AvailabilityOption currentAvail = currentUser.availability;
AvailabilityOption otherAvail = otherUser.availability; AvailabilityOption otherAvail = otherUser.availability;
if (currentAvail == AvailabilityOption.flexible || if (currentAvail != otherAvail &&
otherAvail == AvailabilityOption.flexible || (currentAvail == AvailabilityOption.flexible ||
currentAvail == otherAvail) { otherAvail == AvailabilityOption.flexible)) {
availabilityScore = 3; availabilityScore = 4;
} else { } else {
int availabilityDifference = (currentAvail.index - otherAvail.index).abs(); int availabilityDifference = (currentAvail.index - otherAvail.index).abs();
availabilityScore = 3 - availabilityDifference; // map possible values [0 1 2 3] to points {0 1 3 5]
availabilityScore = (3 - availabilityDifference) * 2 - 1;
} }
// Score on Vision // Score on Vision
@ -223,15 +229,20 @@ double calculateMatchScore(UserProfile currentUser, UserProfile otherUser) {
} }
// Score on Risk // Score on Risk
RiskTolerance currentRisk = currentUser.risk;
RiskTolerance otherRisk = currentUser.risk;
int riskScore = 0; int riskScore = 0;
if (currentUser.risk == otherUser.risk) { if (currentUser.risk == otherUser.risk) {
riskScore = 1; riskScore = 3;
} else {
int riskDifference = (currentRisk.index - otherRisk.index).abs();
riskScore = 3 - riskDifference;
} }
// Score on CorporateCulture // Score on CorporateCulture
int cultureScore = 0; int cultureScore = 0;
if (currentUser.culture == otherUser.culture) { if (currentUser.culture == otherUser.culture) {
cultureScore = 1; cultureScore = 2;
} }
// Score on Communication // Score on Communication
@ -242,43 +253,45 @@ double calculateMatchScore(UserProfile currentUser, UserProfile otherUser) {
// Calc total score. Sum of each score divided by its own max score value, // Calc total score. Sum of each score divided by its own max score value,
// multiplied with its own weight. // multiplied with its own weight.
double totalScore = (distanceWeight * distanceScore / 100) + double totalScore = distanceScore +
(skillWeight * skillsScore / 8) + langScore +
(availabilityWeight * availabilityScore / 3) + sectorScore +
(visionWeight * visionScore / 4) + skillsScore +
(workWeight * workScore / 4) + availabilityScore +
(riskWeight * riskScore) + riskScore +
(cultureWeight * cultureScore) + visionScore +
(communicationWeight * communicationScore); workScore +
cultureScore +
communicationScore;
return totalScore * 100; return min(totalScore, 99.9);
} }
double _distanceToPercentage(double distance) { double _distanceToPoints(double distance) {
// Self predefined data points // Self predefined data points
final List<double> distances = [0, 5, 50, 100, 200]; final List<double> distances = [0, 10, 100, 200, 500, 700, 1000];
final List<double> percentages = [100, 99.5, 95, 90, 50]; final List<double> points = [60, 55, 40, 20, 10, 5, 0];
if (distance.isNaN || distance >= distances.last) { if (distance.isNaN || distance >= distances.last) {
return percentages.last; return points.last;
} else if (distance <= distances[0]) { } else if (distance <= distances[0]) {
return percentages[0]; return points[0];
} }
// Linear interpolation // Linear interpolation
for (int i = 1; i < distances.length; i++) { for (int i = 1; i < distances.length; i++) {
if (distances[i] >= distance) { if (distances[i] >= distance) {
double x0 = distances[i - 1]; double x0 = distances[i - 1];
double y0 = percentages[i - 1]; double y0 = points[i - 1];
double x1 = distances[i]; double x1 = distances[i];
double y1 = percentages[i]; double y1 = points[i];
// Interpolate // Interpolate
double percentage = y0 + (y1 - y0) * (distance - x0) / (x1 - x0); double result = y0 + (y1 - y0) * (distance - x0) / (x1 - x0);
return percentage; return result;
} }
} }
// Fallback return value, though code should never reach here // Fallback return value, though code should never reach here
return percentages.last; // 50 return points.last; // 50
} }