minimal.py
import sys
from munin.easy import EasySession
MY_DATABASE = [
# Artist: Album: Title: Genre:
('Akrea' , 'Lebenslinie' , 'Trugbild' , 'death metal'),
('Vogelfrey' , 'Wiegenfest' , 'Heldentod' , 'folk metal'),
('Letzte Instanz' , 'Götter auf Abruf' , 'Salve te' , 'folk rock'),
('Debauchery' , 'Continue to Kill' , 'Apostle of War' , 'brutal death')
]
session = EasySession()
with session.transaction():
for idx, (artist, album, title, genre) in enumerate(MY_DATABASE):
session.mapping[session.add({
'artist': artist,
'album': album,
'title': title,
'genre': genre
})] = idx
print('2 Recommendations to: {}'.format(MY_DATABASE[0]))
for munin_song in session.recommend_from_seed(session[0], 2):
print(' ', MY_DATABASE[munin_song.uid])
print('3 Recommendations to: {}'.format(MY_DATABASE[1]))
for munin_song in session.recommend_from_seed(session[1], 3):
print(' ', MY_DATABASE[munin_song.uid])
if '--plot' in sys.argv:
print('Now rendering a plot of the relation graph...')
vx = {idx: row[0] for idx, row in enumerate(MY_DATABASE)}
session.database.plot(width=300, height=300, vx_mapping=vx)
complex.py
#!/usr/bin/env python
# encoding: utf-8
import sys
from munin.helper import pairup
from munin.session import Session
from munin.distance import GenreTreeDistance, WordlistDistance
from munin.provider import \
ArtistNormalizeProvider, \
GenreTreeProvider, \
WordlistProvider, \
StemProvider
MY_DATABASE = [(
'Devildriver', # Artist
'Before the Hangmans Noose', # Title
'metal' # Genre
), (
'Das Niveau',
'Beim Pissen gemeuchelt',
'folk'
), (
'We Butter the Bread with Butter',
'Extrem',
'metal'
), (
'Lady Gaga',
'Pokerface',
'pop'
)]
def create_session(name):
print('-- No saved session found, loading new.')
session = Session(
name='demo',
mask={
# Each entry goes like this:
'Genre': pairup(
# Pratice: Go lookup what this Providers does.
GenreTreeProvider(),
# Practice: Same for the DistanceFunction.
GenreTreeDistance(),
# This has the highest rating of the three attributes:
8
),
'Title': pairup(
# We can also compose Provider, so that the left one
# gets the input value, and the right one the value
# the left one processed.
# In this case we first split the title in words,
# then we stem each word.
WordlistProvider() | StemProvider(),
WordlistDistance(),
1
),
'Artist': pairup(
# If no Provider (None) is given the value is forwarded as-is.
# Here we just use the default provider, but enable
# compression. Values are saved once and are givean an ID.
# Duplicate items get the same ID always.
# You can trade off memory vs. speed with this.
ArtistNormalizeProvider(compress=True),
# If not DistanceFunctions is given, all values are
# compare with __eq__ - which might give bad results.
None,
1
)
}
)
# As in our first example we fill the session, but we dont insert the full
# database, we leave out the last song:
with session.transaction():
for idx, (artist, title, genre) in enumerate(MY_DATABASE[:3]):
# Notice how we use the uppercase keys like above:
session.mapping[session.add({
'Genre': genre,
'Title': title,
'Artist': artist,
})] = idx
return session
def print_recommendations(session, n=5):
# A generator that yields at max 20 songs.
recom_generator = session.recommend_from_heuristic(number=n)
seed_song = next(recom_generator)
print('Recommendations to #{}:'.format(seed_song.uid))
for munin_song in recom_generator:
print(' normalized values:')
# Let's take
for attribute, normalized_value in munin_song.items():
print(' {:<7s}: {:<20s}'.format(attribute, normalized_value))
original_song = MY_DATABASE[session.mapping[munin_song.uid]]
print(' original values:')
print(' Artist :', original_song[0])
print(' Album :', original_song[1])
print(' Genre :', original_song[2])
print()
if __name__ == '__main__':
print('The database:')
for idx, song in enumerate(MY_DATABASE):
print(' #{} {}'.format(idx, song))
print()
# Perhaps we already had an prior session?
session = Session.from_name('demo') or create_session('demo')
rules = list(session.rule_index)
if rules:
print('Association Rules:')
for left, right, support, rating in rules:
print(' {:>10s} <-> {:<10s} [supp={:>5d}, rating={:.5f}]'.format(
str([song.uid for song in left]),
str([song.uid for song in right]),
support, rating
))
print()
print_recommendations(session)
# Let's add some history:
for munin_uid in [0, 2, 0, 0, 2]:
session.feed_history(munin_uid)
print('Playcounts:')
for song, count in session.playcounts().items():
print(' #{} was played {}x times'.format(song.uid, count))
# Let's insert a new song that will be in the graph on the next run:
if len(session) != len(MY_DATABASE):
with session.fix_graph():
session.mapping[session.insert({
'Genre': MY_DATABASE[-1][2],
'Title': MY_DATABASE[-1][1],
'Artist': MY_DATABASE[-1][0]
})] = 3
if '--plot' in sys.argv:
session.database.plot()
# Save it under ~/.cache/libmunin/demo
session.save()