🌑

ArsFy.

Recommendation Algorithm Based on Tag Multidimensional Vector

This is a simple Tag-based recommendation algorithm, uses a point system to recommend similar content.

I will first describe how this algorithm is implemented, then release the code.

Example

1. User Model

Data sources can be reading records, favourites… We need to get a weighted model of user preferences.

Favorite Tag:

  • #big (Weights 2, ≈16.7%)
  • #red (Weights 1, ≈8.3%)
  • #plant (Weights 1, ≈8.3%)
  • #food (Weights 4, ≈33.3%)
  • #round (Weights 2, ≈16.7%)
  • #square (Weight 2, ≈16.7%)
{
    "big": 0.167,
    "red": 0.083,
    "plant": 0.083,
    "food": 0.333,
    "round": 0.167,
    "square": 0.167
}

Construct a simple model by weighting to describe user preferences.

2. Point system

There are several values, each with a different weights, and the tag that appears most often is clearly more popular with users.

We can use the weights as points to give a standardised score for each article.

Here are three articles:

["watermelon", "plant", "food", "round", "big"]
["freezer", "big", "artefact", "not food", "spuare"]
["apple", "food", "round", "plant"]

Similar output:

  1. plant (0.083) + food (0.333) + round (0.167) + big (0.167) = 0.75
  2. big (0.167) + spuare (0.167) = 0.334
  3. food (0.333) + round (0.167) + plant (0.083) = 0.583

The highest score here is 1, so it will be the first recommendation.

We can see that there are no restrictions on weighting and no deductions, which makes it easy to take a few hours of free time out of work to make it happen.

Code

In this example, I can using Golang as the programming language.

1. GetData

We need to get tags of all articles. If your data is not very large, you can get it at one time. If you need to, you can choose to divide it into multiple times.

type DbTag struct {
    Id  int    `db:"id"`
    Tags []uint8 `db:"tags"`
}

type TagList struct {
    Id int
    Tags []string
}

func getTags() []TagList {
    var allTags []DbTag
    err := Db.Select(&allTags, "SELECT id, tags FROM page")
    if err != nil {
        fmt.Println("exec failed", err)
        return
    }

    var taglist []TagList
    for i := range allTags {
        var tags []string
        json.Unmarshal(allTags[i].Tags, &tags)
        taglist = append(taglist, TagList{Id: allTags[i].Id, Tags: tags})
    }

    return taglist
}

Use user’s favorite article id to get article tag.

var ftags []DbTag
err := Db.Select(&ftags, "SELECT id, tags FROM page WHERE `id` IN (1, 2, 3, 4)") // ID
if err != nil {
    fmt.Println("exec failed", err)
    return
}

2. Get Model

Take three decimal places for each value to prevent it from becoming too long.

This function will output a string and float64 key-value pair, like JSON example above.

func model(taglist []string) map[string]float64 {
	taglistLen := len(taglist)
	clist := make(map[string]int)
	rlist := make(map[string]float64)
	for _, j := range taglist {
		clist[j]++
	}
	for i := range clist {
		pow10_3 := math.Pow10(3)
		rlist[i] = math.Trunc(((float64(clist[i])/float64(taglistLen))+0.5/pow10_3)*pow10_3) / pow10_3
	}

	return rlist
}

3. Calculate points

Calculate number of points for each article

allTag := getTags()

articlelist := make(map[int]float64)
for i := range allTag {
    var point float64 = 0.000
    thisTagList := allTag[i].Tags
    for ii := range thisTagList {
        point += user[thisTagList[ii]]
    }
    articlelist[allTag[i].Id] = point
}

4. Sort

Once you have sorted the articles, our work is done.

if you only want to show the top ones, you can filter them yourself, don’t forget to delete the articles that the user has bookmarked.

type Pair struct {
	Key   int
	Value float64
}

func rankByWordCount(wordFrequencies map[int]float64) PairList {
	pl := make(PairList, len(wordFrequencies))
	i := 0
	for k, v := range wordFrequencies {
		pl[i] = Pair{k, v}
		i++
	}
	sort.Sort(sort.Reverse(pl))
	return pl
}

...

rwclist := rankByWordCount(articlelist)
fmt.Println(rwclist)

, — Feb 19, 2022