diff --git a/lastfm/tag.py b/lastfm/tag.py index ab3351f..21ee6b3 100644 --- a/lastfm/tag.py +++ b/lastfm/tag.py @@ -24,7 +24,8 @@ class Tag(LastfmBase, Cacheable, Searchable): self._streamable = streamable self._stats = stats and Stats( subject = self, - count = stats.count + count = stats.count, + rank = stats.rank ) @property diff --git a/lastfm/user.py b/lastfm/user.py index 586f7c3..ecd217d 100644 --- a/lastfm/user.py +++ b/lastfm/user.py @@ -584,6 +584,29 @@ class User(LastfmBase, Cacheable, Shoutable): except LastfmError: pass return gen() + + def get_weekly_tag_chart(self, + start = None, + end = None): + WeeklyChart._check_weekly_chart_params({}, start, end) + return WeeklyTagChart.get(self._api, self, start, end) + + @LastfmBase.cached_property + def recent_weekly_tag_chart(self): + return self.get_weekly_tag_chart() + + @LastfmBase.cached_property + def weekly_tag_chart_list(self): + wcl = list(self.weekly_chart_list) + wcl.reverse() + @lazylist + def gen(lst): + for wc in wcl: + try: + yield self.get_weekly_tag_chart(wc.start, wc.end) + except LastfmError: + pass + return gen() def compare(self, other, limit = None): return Tasteometer.compare(self._api, @@ -941,4 +964,4 @@ from lastfm.stats import Stats from lastfm.tag import Tag from lastfm.tasteometer import Tasteometer from lastfm.track import Track -from lastfm.weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart +from lastfm.weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart, WeeklyTagChart diff --git a/lastfm/weeklychart.py b/lastfm/weeklychart.py index 662fb3c..3d2b8a5 100644 --- a/lastfm/weeklychart.py +++ b/lastfm/weeklychart.py @@ -253,6 +253,98 @@ class WeeklyTrackChart(WeeklyChart): for t in data.findall('track') ] ) + +class WeeklyTagChart(WeeklyChart): + """A class for representing the weekly tag charts""" + def init(self, subject, start, end, tags, stats): + super(WeeklyTagChart, self).init(subject, start, end, stats) + self._tags = tags + + @property + def tags(self): + return self._tags + + @staticmethod + def get(api, subject, start, end): + w = WeeklyChart( + subject = subject, + start = start, + end = end, + ) + max_tag_count = 3 + global_top_tags = api.get_global_top_tags() + from collections import defaultdict + + wac = subject.get_weekly_artist_chart(start, end) + all_tags = defaultdict(lambda:0) + tag_weights = defaultdict(lambda:0) + total_playcount = 0 + artist_count = 0 + for artist in wac.artists: + artist_count += 1 + total_playcount += artist.stats.playcount + tag_count = 0 + for tag in artist.top_tags: + if tag not in global_top_tags: continue + if tag_count >= max_tag_count: break + all_tags[tag] += 1 + tag_count += 1 + + artist_pp = artist.stats.playcount/float(wac.stats.playcount) + cumulative_pp = total_playcount/float(wac.stats.playcount) + if (cumulative_pp > 0.75 or artist_pp < 0.01) and artist_count > 10: + break + + for artist in wac.artists[:artist_count]: + artist_pp = artist.stats.playcount/float(wac.stats.playcount) + tf = 1/float(max_tag_count) + tag_count = 0 + weighted_tfidfs = {} + for tag in artist.top_tags: + if tag not in global_top_tags: continue + if tag_count >= max_tag_count: break + + df = all_tags[tag]/float(artist_count) + tfidf = tf/df + weighted_tfidf = float(max_tag_count - tag_count)*tfidf + weighted_tfidfs[tag.name] = weighted_tfidf + tag_count += 1 + + sum_weighted_tfidfs = sum(weighted_tfidfs.values()) + for tag in weighted_tfidfs: + tag_weights[tag] += weighted_tfidfs[tag]/sum_weighted_tfidfs*artist_pp + + artist_pp = artist.stats.playcount/float(wac.stats.playcount) + + tag_weights_sum = sum(tag_weights.values()) + tag_weights = tag_weights.items() + tag_weights.sort(key=lambda x:x[1], reverse=True) + for i in xrange(len(tag_weights)): + tag, weight = tag_weights[i] + tag_weights[i] = (tag, weight, i+1) + + return WeeklyTagChart( + subject = subject, + start = wac.start, + end = wac.end, + stats = Stats( + subject = subject, + playcount = 1000 + ), + tags = [ + Tag( + api, + subject = w, + name = tag, + stats = Stats( + subject = tag, + rank = rank, + count = int(round(1000*weight/tag_weights_sum)), + ) + ) + for (tag, weight, rank) in tag_weights + ] + ) from datetime import datetime import calendar @@ -261,4 +353,5 @@ from lastfm.album import Album from lastfm.artist import Artist from lastfm.error import InvalidParametersError from lastfm.stats import Stats -from lastfm.track import Track \ No newline at end of file +from lastfm.track import Track +from lastfm.tag import Tag \ No newline at end of file