add music analyzer
This commit is contained in:
parent
300cd22d50
commit
8ab6678ee1
20
data/data.txt
Normal file
20
data/data.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
1|Smells Like Teen Spirit|Nirvana|Nevermind|rock|301|980000|75000|1991-09-10|false
|
||||||
|
2|Blinding Lights|The Weeknd|After Hours|pop|200|1500000|120000|2019-11-29|false
|
||||||
|
3|Lose Yourself|Eminem|8 Mile|hip-hop|326|1200000|98000|2002-10-28|true
|
||||||
|
4|Levels|Avicii|True|electronic|193|870000|65000|2011-10-28|false
|
||||||
|
5|Come As You Are|Nirvana|Nevermind|rock|219|750000|58000|1992-03-02|false
|
||||||
|
6|Starboy|The Weeknd|Starboy|pop|230|1100000|88000|2016-09-22|true
|
||||||
|
7|Rap God|Eminem|The Marshall Mathers LP2|hip-hop|363|950000|82000|2013-10-14|true
|
||||||
|
8|Wake Me Up|Avicii|True|electronic|247|920000|71000|2013-06-17|false
|
||||||
|
9|In Bloom|Nirvana|Nevermind|rock|255|620000|47000|1992-11-30|false
|
||||||
|
10|Save Your Tears|The Weeknd|After Hours|pop|215|1050000|91000|2020-08-06|false
|
||||||
|
11|Without Me|Eminem|The Eminem Show|hip-hop|290|880000|69000|2002-05-14|true
|
||||||
|
12|Hey You|Pink Floyd|The Wall|rock|277|540000|49000|1979-11-30|false
|
||||||
|
13|Wish You Were Here|Pink Floyd|Wish You Were Here|rock|334|670000|61000|1975-09-12|false
|
||||||
|
14|Scared to Be Lonely|Avicii|Avicii 01|electronic|211|430000|38000|2017-02-03|false
|
||||||
|
15|Die For You|The Weeknd|Starboy|pop|260|990000|95000|2016-11-25|false
|
||||||
|
16|Godzilla|Eminem|Music to Be Murdered By|hip-hop|213|760000|55000|2020-01-17|true
|
||||||
|
17|Money|Pink Floyd|The Dark Side of the Moon|rock|382|590000|53000|1973-03-01|false
|
||||||
|
18|The Night|Avicii|Stories|electronic|198|380000|29000|2015-10-02|false
|
||||||
|
19|Lithium|Nirvana|Nevermind|rock|256|690000|52000|1992-07-21|false
|
||||||
|
20|Take My Breath|The Weeknd|Dawn FM|pop|223|820000|74000|2021-08-06|false
|
||||||
241
music_analyzer.py
Normal file
241
music_analyzer.py
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def load_tracks(filepath):
|
||||||
|
"""Загружает треки из txt файла. При ошибке возвращает пустой список."""
|
||||||
|
tracks = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(filepath, "r", encoding="utf-8") as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
# пропускаем пустые строки
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
parts = line.split("|")
|
||||||
|
|
||||||
|
# проверяем что полей ровно 10
|
||||||
|
if len(parts) != 10:
|
||||||
|
print("Пропускаю некорректную строку:", line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
track = {
|
||||||
|
"track_id": int(parts[0]),
|
||||||
|
"title": parts[1],
|
||||||
|
"artist": parts[2],
|
||||||
|
"album": parts[3],
|
||||||
|
"genre": parts[4],
|
||||||
|
"duration_seconds": int(parts[5]),
|
||||||
|
"plays": int(parts[6]),
|
||||||
|
"likes": int(parts[7]),
|
||||||
|
"release_date": parts[8],
|
||||||
|
"explicit": parts[9] == "true"
|
||||||
|
}
|
||||||
|
tracks.append(track)
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Файл не найден:", filepath)
|
||||||
|
return []
|
||||||
|
|
||||||
|
return tracks
|
||||||
|
|
||||||
|
|
||||||
|
def filter_by_genre(tracks, genre):
|
||||||
|
"""Возвращает треки с указанным жанром."""
|
||||||
|
result = []
|
||||||
|
for track in tracks:
|
||||||
|
if track["genre"].lower() == genre.lower():
|
||||||
|
result.append(track)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def filter_by_duration(tracks, min_sec, max_sec):
|
||||||
|
"""Возвращает треки с длительностью в диапазоне [min_sec, max_sec]."""
|
||||||
|
result = []
|
||||||
|
for track in tracks:
|
||||||
|
if min_sec <= track["duration_seconds"] <= max_sec:
|
||||||
|
result.append(track)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_top_tracks(tracks, n):
|
||||||
|
"""Возвращает n треков с наибольшим числом прослушиваний."""
|
||||||
|
sorted_tracks = sorted(tracks, key=lambda t: t["plays"], reverse=True)
|
||||||
|
return sorted_tracks[:n]
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_artist_stats(tracks, artist):
|
||||||
|
"""Возвращает статистику по исполнителю."""
|
||||||
|
artist_tracks = []
|
||||||
|
for track in tracks:
|
||||||
|
if track["artist"].lower() == artist.lower():
|
||||||
|
artist_tracks.append(track)
|
||||||
|
|
||||||
|
if len(artist_tracks) == 0:
|
||||||
|
return {
|
||||||
|
"total_tracks": 0,
|
||||||
|
"total_plays": 0,
|
||||||
|
"total_likes": 0,
|
||||||
|
"avg_duration_seconds": 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
total_plays = 0
|
||||||
|
total_likes = 0
|
||||||
|
total_duration = 0
|
||||||
|
|
||||||
|
for track in artist_tracks:
|
||||||
|
total_plays += track["plays"]
|
||||||
|
total_likes += track["likes"]
|
||||||
|
total_duration += track["duration_seconds"]
|
||||||
|
|
||||||
|
avg_duration = total_duration / len(artist_tracks)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"total_tracks": len(artist_tracks),
|
||||||
|
"total_plays": total_plays,
|
||||||
|
"total_likes": total_likes,
|
||||||
|
"avg_duration_seconds": round(avg_duration, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_unique_genres(tracks):
|
||||||
|
"""Возвращает отсортированный список уникальных жанров."""
|
||||||
|
genres = []
|
||||||
|
for track in tracks:
|
||||||
|
if track["genre"] not in genres:
|
||||||
|
genres.append(track["genre"])
|
||||||
|
return sorted(genres)
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_like_rate(tracks):
|
||||||
|
"""Считает коэффициент лайков для каждого трека."""
|
||||||
|
result = []
|
||||||
|
for track in tracks:
|
||||||
|
if track["plays"] == 0:
|
||||||
|
continue
|
||||||
|
rate = track["likes"] / track["plays"] * 100
|
||||||
|
rate = round(rate, 2)
|
||||||
|
result.append((track["title"], rate))
|
||||||
|
|
||||||
|
result = sorted(result, key=lambda x: x[1], reverse=True)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def group_by_artist(tracks):
|
||||||
|
"""Группирует треки по исполнителю."""
|
||||||
|
result = {}
|
||||||
|
for track in tracks:
|
||||||
|
artist = track["artist"]
|
||||||
|
if artist not in result:
|
||||||
|
result[artist] = []
|
||||||
|
result[artist].append(track)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def filter_by_date_range(tracks, date_from, date_to):
|
||||||
|
"""Возвращает треки выпущенные в диапазоне дат."""
|
||||||
|
result = []
|
||||||
|
for track in tracks:
|
||||||
|
if date_from <= track["release_date"] <= date_to:
|
||||||
|
result.append(track)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def save_report(data, filepath):
|
||||||
|
"""Сохраняет список треков в txt файл."""
|
||||||
|
try:
|
||||||
|
directory = os.path.dirname(filepath)
|
||||||
|
if directory and not os.path.exists(directory):
|
||||||
|
os.makedirs(directory)
|
||||||
|
|
||||||
|
with open(filepath, "w", encoding="utf-8") as f:
|
||||||
|
for track in data:
|
||||||
|
line = "{title} | {artist} | {genre} | {plays} прослушиваний\n".format(
|
||||||
|
title=track["title"],
|
||||||
|
artist=track["artist"],
|
||||||
|
genre=track["genre"],
|
||||||
|
plays=track["plays"]
|
||||||
|
)
|
||||||
|
f.write(line)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("Ошибка при сохранении файла:", e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# 1. Загружаем треки
|
||||||
|
tracks = load_tracks("data/data.txt")
|
||||||
|
|
||||||
|
if len(tracks) == 0:
|
||||||
|
print("Нет данных для обработки")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 2. Общее количество треков и жанры
|
||||||
|
print("=" * 40)
|
||||||
|
print("Всего треков:", len(tracks))
|
||||||
|
genres = get_unique_genres(tracks)
|
||||||
|
print("Жанры:", ", ".join(genres))
|
||||||
|
|
||||||
|
# 3. Фильтрация по жанру
|
||||||
|
print("=" * 40)
|
||||||
|
rock_tracks = filter_by_genre(tracks, "rock")
|
||||||
|
print("Треков в жанре rock:", len(rock_tracks))
|
||||||
|
|
||||||
|
# 4. Топ-5 треков по прослушиваниям
|
||||||
|
print("=" * 40)
|
||||||
|
print("Топ-5 треков по прослушиваниям:")
|
||||||
|
top5 = get_top_tracks(tracks, 5)
|
||||||
|
for track in top5:
|
||||||
|
print(" -", track["title"], "—", track["plays"], "прослушиваний")
|
||||||
|
|
||||||
|
# 5. Статистика исполнителя
|
||||||
|
print("=" * 40)
|
||||||
|
first_artist = tracks[0]["artist"]
|
||||||
|
stats = calculate_artist_stats(tracks, first_artist)
|
||||||
|
print("Статистика исполнителя:", first_artist)
|
||||||
|
print(" - Треков:", stats["total_tracks"])
|
||||||
|
print(" - Прослушиваний:", stats["total_plays"])
|
||||||
|
print(" - Лайков:", stats["total_likes"])
|
||||||
|
print(" - Средняя длительность (сек):", stats["avg_duration_seconds"])
|
||||||
|
|
||||||
|
# 6. Фильтрация по длительности
|
||||||
|
print("=" * 40)
|
||||||
|
mid_tracks = filter_by_duration(tracks, 180, 240)
|
||||||
|
print("Треков длительностью 3-4 минуты:", len(mid_tracks))
|
||||||
|
|
||||||
|
# 7. Топ-5 по коэффициенту лайков
|
||||||
|
print("=" * 40)
|
||||||
|
print("Топ-5 треков по лайкам:")
|
||||||
|
like_rates = calculate_like_rate(tracks)
|
||||||
|
for title, rate in like_rates[:5]:
|
||||||
|
print(" -", title, "—", rate, "%")
|
||||||
|
|
||||||
|
# 8. Фильтрация по дате
|
||||||
|
print("=" * 40)
|
||||||
|
date_filtered = filter_by_date_range(tracks, "2020-01-01", "2024-12-31")
|
||||||
|
print("Треков за период 2020-2024:", len(date_filtered))
|
||||||
|
|
||||||
|
# 9. Группировка по исполнителям
|
||||||
|
print("=" * 40)
|
||||||
|
print("Треков по исполнителям:")
|
||||||
|
grouped = group_by_artist(tracks)
|
||||||
|
for artist, artist_tracks in grouped.items():
|
||||||
|
print(" -", artist, ":", len(artist_tracks), "треков")
|
||||||
|
|
||||||
|
# 10. Сохраняем топ-10 в файл
|
||||||
|
print("=" * 40)
|
||||||
|
top10 = get_top_tracks(tracks, 10)
|
||||||
|
success = save_report(top10, "results/top_tracks.txt")
|
||||||
|
if success:
|
||||||
|
print("Топ-10 треков сохранён в results/top_tracks.txt")
|
||||||
|
else:
|
||||||
|
print("Не удалось сохранить файл")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
10
results/top_tracks.txt
Normal file
10
results/top_tracks.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Blinding Lights | The Weeknd | pop | 1500000 прослушиваний
|
||||||
|
Lose Yourself | Eminem | hip-hop | 1200000 прослушиваний
|
||||||
|
Starboy | The Weeknd | pop | 1100000 прослушиваний
|
||||||
|
Save Your Tears | The Weeknd | pop | 1050000 прослушиваний
|
||||||
|
Die For You | The Weeknd | pop | 990000 прослушиваний
|
||||||
|
Smells Like Teen Spirit | Nirvana | rock | 980000 прослушиваний
|
||||||
|
Rap God | Eminem | hip-hop | 950000 прослушиваний
|
||||||
|
Wake Me Up | Avicii | electronic | 920000 прослушиваний
|
||||||
|
Without Me | Eminem | hip-hop | 880000 прослушиваний
|
||||||
|
Levels | Avicii | electronic | 870000 прослушиваний
|
||||||
Loading…
Reference in New Issue
Block a user