用Python分析你的Spotify/网易云音乐听歌数据

目录

  • 用Python分析你的Spotify/网易云音乐听歌数据
    • [1. 引言:音乐数据分析的价值与意义](#1. 引言:音乐数据分析的价值与意义)
      • [1.1 音乐数据的商业价值与个人洞察](#1.1 音乐数据的商业价值与个人洞察)
      • [1.2 技术栈选择与优势](#1.2 技术栈选择与优势)
    • [2. 数据获取与预处理](#2. 数据获取与预处理)
      • [2.1 Spotify数据获取](#2.1 Spotify数据获取)
      • [2.2 网易云音乐数据获取](#2.2 网易云音乐数据获取)
    • [3. 数据分析核心引擎](#3. 数据分析核心引擎)
      • [3.1 音乐特征分析](#3.1 音乐特征分析)
    • [4. 高级分析与机器学习](#4. 高级分析与机器学习)
      • [4.1 情绪分析与模式识别](#4.1 情绪分析与模式识别)
    • [5. 完整应用集成](#5. 完整应用集成)
      • [5.1 主应用和报告生成](#5.1 主应用和报告生成)
    • [6. 总结](#6. 总结)
      • [6.1 项目成果](#6.1 项目成果)
        • [✅ 数据收集能力](#✅ 数据收集能力)
        • [✅ 分析功能](#✅ 分析功能)
        • [✅ 可视化与报告](#✅ 可视化与报告)
      • [6.2 技术亮点](#6.2 技术亮点)
      • [6.3 数学与算法原理](#6.3 数学与算法原理)
      • [6.4 实际应用价值](#6.4 实际应用价值)

『宝藏代码胶囊开张啦!』------ 我的 CodeCapsule 来咯!✨写代码不再头疼!我的新站点 CodeCapsule 主打一个 "白菜价"+"量身定制 "!无论是卡脖子的毕设/课设/文献复现 ,需要灵光一现的算法改进 ,还是想给项目加个"外挂",这里都有便宜又好用的代码方案等你发现!低成本,高适配,助你轻松通关!速来围观 👉 CodeCapsule官网

用Python分析你的Spotify/网易云音乐听歌数据

1. 引言:音乐数据分析的价值与意义

1.1 音乐数据的商业价值与个人洞察

在流媒体音乐时代,每个用户每年平均产生超过10,000条听歌记录。这些数据不仅是音乐平台推荐算法的核心,更是了解个人音乐品味、情绪变化和生活习惯的宝贵资源。根据2023年音乐产业报告,数据分析驱动的个性化推荐为音乐流媒体平台贡献了超过40%的用户活跃度。

python 复制代码
# 音乐数据分析的应用场景
analysis_applications = {
    "个人洞察": "了解自己的音乐品味演变和情绪模式",
    "音乐发现": "发现新的艺术家和音乐类型", 
    "情绪分析": "通过音乐偏好分析心理状态变化",
    "社交分享": "生成个性化的年度音乐报告",
    "学术研究": "研究音乐偏好与文化、年龄的关系"
}

1.2 技术栈选择与优势

我们选择Python进行音乐数据分析具有显著优势:

python 复制代码
# Python音乐数据分析技术栈
tech_stack = {
    "数据获取": {
        "Spotify API": "完整的官方API支持",
        "网易云音乐API": "第三方开源API库",
        "pandas": "高效的数据处理和分析"
    },
    "数据分析": {
        "scikit-learn": "机器学习和聚类分析",
        "numpy": "数值计算和统计处理",
        "matplotlib": "数据可视化和图表生成"
    },
    "高级功能": {
        "librosa": "音频特征提取",
        "wordcloud": "歌词文本分析",
        "networkx": "艺术家关系网络分析"
    }
}

2. 数据获取与预处理

2.1 Spotify数据获取

python 复制代码
#!/usr/bin/env python3
"""
Spotify听歌数据获取模块
通过Spotify Web API获取用户的听歌历史和分析数据
"""

import spotipy
from spotipy.oauth2 import SpotifyOAuth
import pandas as pd
import json
import time
from datetime import datetime, timedelta
from typing import List, Dict, Optional, Any
from dataclasses import dataclass
import os
from pathlib import Path

@dataclass
class SpotifyConfig:
    """Spotify API配置类"""
    client_id: str
    client_secret: str
    redirect_uri: str = "http://localhost:8888/callback"
    scope: str = "user-read-recently-played user-top-read user-library-read playlist-read-private"

class SpotifyDataCollector:
    """
    Spotify数据收集器
    负责从Spotify API获取用户的听歌数据
    """
    
    def __init__(self, config: SpotifyConfig):
        """
        初始化数据收集器
        
        Args:
            config: Spotify API配置
        """
        self.config = config
        self.sp = self._authenticate()
        self.data_dir = Path("spotify_data")
        self.data_dir.mkdir(exist_ok=True)
    
    def _authenticate(self) -> spotipy.Spotify:
        """
        Spotify API认证
        
        Returns:
            spotipy.Spotify: 认证后的Spotify客户端
        """
        try:
            sp = spotipy.Spotify(auth_manager=SpotifyOAuth(
                client_id=self.config.client_id,
                client_secret=self.config.client_secret,
                redirect_uri=self.config.redirect_uri,
                scope=self.config.scope
            ))
            return sp
        except Exception as e:
            raise Exception(f"Spotify认证失败: {e}")
    
    def get_recently_played(self, limit: int = 50) -> List[Dict]:
        """
        获取最近播放的歌曲
        
        Args:
            limit: 获取的记录数量
            
        Returns:
            List[Dict]: 最近播放的歌曲列表
        """
        try:
            results = self.sp.current_user_recently_played(limit=limit)
            tracks = []
            
            for item in results['items']:
                track = item['track']
                played_at = datetime.fromisoformat(item['played_at'].replace('Z', '+00:00'))
                
                track_data = {
                    'played_at': played_at,
                    'track_id': track['id'],
                    'track_name': track['name'],
                    'artist_id': track['artists'][0]['id'],
                    'artist_name': track['artists'][0]['name'],
                    'album_id': track['album']['id'],
                    'album_name': track['album']['name'],
                    'duration_ms': track['duration_ms'],
                    'popularity': track['popularity'],
                    'explicit': track['explicit']
                }
                tracks.append(track_data)
            
            return tracks
            
        except Exception as e:
            print(f"获取最近播放记录失败: {e}")
            return []
    
    def get_top_tracks(self, time_range: str = 'medium_term', limit: int = 50) -> List[Dict]:
        """
        获取用户最常听的歌曲
        
        Args:
            time_range: 时间范围 (short_term, medium_term, long_term)
            limit: 获取的记录数量
            
        Returns:
            List[Dict]: 最常听的歌曲列表
        """
        try:
            results = self.sp.current_user_top_tracks(
                time_range=time_range, 
                limit=limit
            )
            
            tracks = []
            for track in results['items']:
                # 获取音频特征
                audio_features = self.sp.audio_features([track['id']])[0]
                
                track_data = {
                    'track_id': track['id'],
                    'track_name': track['name'],
                    'artist_id': track['artists'][0]['id'],
                    'artist_name': track['artists'][0]['name'],
                    'album_id': track['album']['id'],
                    'album_name': track['album']['name'],
                    'duration_ms': track['duration_ms'],
                    'popularity': track['popularity'],
                    'explicit': track['explicit'],
                    'danceability': audio_features['danceability'] if audio_features else None,
                    'energy': audio_features['energy'] if audio_features else None,
                    'key': audio_features['key'] if audio_features else None,
                    'loudness': audio_features['loudness'] if audio_features else None,
                    'mode': audio_features['mode'] if audio_features else None,
                    'speechiness': audio_features['speechiness'] if audio_features else None,
                    'acousticness': audio_features['acousticness'] if audio_features else None,
                    'instrumentalness': audio_features['instrumentalness'] if audio_features else None,
                    'liveness': audio_features['liveness'] if audio_features else None,
                    'valence': audio_features['valence'] if audio_features else None,
                    'tempo': audio_features['tempo'] if audio_features else None,
                    'time_signature': audio_features['time_signature'] if audio_features else None
                }
                tracks.append(track_data)
            
            return tracks
            
        except Exception as e:
            print(f"获取热门歌曲失败: {e}")
            return []
    
    def get_top_artists(self, time_range: str = 'medium_term', limit: int = 50) -> List[Dict]:
        """
        获取用户最常听的艺术家
        
        Args:
            time_range: 时间范围
            limit: 获取的记录数量
            
        Returns:
            List[Dict]: 最常听的艺术家列表
        """
        try:
            results = self.sp.current_user_top_artists(
                time_range=time_range, 
                limit=limit
            )
            
            artists = []
            for artist in results['items']:
                artist_data = {
                    'artist_id': artist['id'],
                    'artist_name': artist['name'],
                    'genres': artist['genres'],
                    'popularity': artist['popularity'],
                    'followers': artist['followers']['total']
                }
                artists.append(artist_data)
            
            return artists
            
        except Exception as e:
            print(f"获取热门艺术家失败: {e}")
            return []
    
    def get_saved_tracks(self, limit: int = 50) -> List[Dict]:
        """
        获取用户保存的歌曲
        
        Args:
            limit: 获取的记录数量
            
        Returns:
            List[Dict]: 保存的歌曲列表
        """
        try:
            results = self.sp.current_user_saved_tracks(limit=limit)
            
            tracks = []
            for item in results['items']:
                track = item['track']
                added_at = datetime.fromisoformat(item['added_at'].replace('Z', '+00:00'))
                
                track_data = {
                    'added_at': added_at,
                    'track_id': track['id'],
                    'track_name': track['name'],
                    'artist_name': track['artists'][0]['name'],
                    'album_name': track['album']['name'],
                    'popularity': track['popularity']
                }
                tracks.append(track_data)
            
            return tracks
            
        except Exception as e:
            print(f"获取保存歌曲失败: {e}")
            return []
    
    def collect_all_data(self) -> Dict[str, pd.DataFrame]:
        """
        收集所有类型的听歌数据
        
        Returns:
            Dict[str, pd.DataFrame]: 包含所有数据的字典
        """
        print("开始收集Spotify听歌数据...")
        
        data_frames = {}
        
        # 收集最近播放
        print("📻 获取最近播放记录...")
        recent_tracks = self.get_recently_played(limit=50)
        if recent_tracks:
            data_frames['recent_tracks'] = pd.DataFrame(recent_tracks)
        
        # 收集热门歌曲
        print("🔥 获取热门歌曲...")
        for time_range in ['short_term', 'medium_term', 'long_term']:
            top_tracks = self.get_top_tracks(time_range=time_range, limit=50)
            if top_tracks:
                df = pd.DataFrame(top_tracks)
                df['time_range'] = time_range
                key = f'top_tracks_{time_range}'
                data_frames[key] = df
        
        # 收集热门艺术家
        print("🎤 获取热门艺术家...")
        for time_range in ['short_term', 'medium_term', 'long_term']:
            top_artists = self.get_top_artists(time_range=time_range, limit=50)
            if top_artists:
                df = pd.DataFrame(top_artists)
                df['time_range'] = time_range
                key = f'top_artists_{time_range}'
                data_frames[key] = df
        
        # 收集保存的歌曲
        print("💾 获取保存的歌曲...")
        saved_tracks = self.get_saved_tracks(limit=50)
        if saved_tracks:
            data_frames['saved_tracks'] = pd.DataFrame(saved_tracks)
        
        # 保存数据到文件
        self._save_dataframes(data_frames)
        
        print(f"✅ 数据收集完成! 共收集 {len(data_frames)} 个数据集")
        return data_frames
    
    def _save_dataframes(self, data_frames: Dict[str, pd.DataFrame]):
        """
        保存DataFrame到CSV文件
        
        Args:
            data_frames: 包含DataFrame的字典
        """
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        for name, df in data_frames.items():
            filename = self.data_dir / f"{name}_{timestamp}.csv"
            df.to_csv(filename, index=False, encoding='utf-8')
            print(f"💾 保存: {filename}")
    
    def load_latest_data(self) -> Dict[str, pd.DataFrame]:
        """
        加载最新的数据文件
        
        Returns:
            Dict[str, pd.DataFrame]: 包含所有数据的字典
        """
        data_frames = {}
        
        if not self.data_dir.exists():
            print("❌ 数据目录不存在")
            return data_frames
        
        # 找到最新的文件
        csv_files = list(self.data_dir.glob("*.csv"))
        if not csv_files:
            print("❌ 没有找到数据文件")
            return data_frames
        
        # 按文件名分组(去掉时间戳)
        file_groups = {}
        for file in csv_files:
            base_name = '_'.join(file.stem.split('_')[:-1])  # 去掉时间戳
            if base_name not in file_groups:
                file_groups[base_name] = []
            file_groups[base_name].append(file)
        
        # 加载每个组的最新文件
        for base_name, files in file_groups.items():
            latest_file = max(files, key=lambda x: x.stat().st_mtime)
            df = pd.read_csv(latest_file)
            data_frames[base_name] = df
            print(f"📂 加载: {latest_file}")
        
        return data_frames

# 配置管理和演示
def setup_spotify_config() -> SpotifyConfig:
    """
    设置Spotify配置
    
    Returns:
        SpotifyConfig: 配置对象
    """
    # 从环境变量获取配置
    client_id = os.getenv('SPOTIFY_CLIENT_ID')
    client_secret = os.getenv('SPOTIFY_CLIENT_SECRET')
    
    if not client_id or not client_secret:
        print("❌ 请设置Spotify API凭据:")
        print("   export SPOTIFY_CLIENT_ID=your_client_id")
        print("   export SPOTIFY_CLIENT_SECRET=your_client_secret")
        raise ValueError("缺少Spotify API配置")
    
    return SpotifyConfig(
        client_id=client_id,
        client_secret=client_secret
    )

def demo_spotify_collection():
    """演示Spotify数据收集"""
    print("Spotify数据收集演示")
    print("=" * 50)
    
    try:
        # 设置配置
        config = setup_spotify_config()
        
        # 创建收集器
        collector = SpotifyDataCollector(config)
        
        # 测试认证
        print("🔐 测试Spotify认证...")
        user_info = collector.sp.current_user()
        print(f"✅ 认证成功! 用户: {user_info['display_name']}")
        
        # 收集数据
        data = collector.collect_all_data()
        
        # 显示数据统计
        print("\n📊 数据收集统计:")
        for name, df in data.items():
            print(f"  {name}: {len(df)} 条记录")
        
        return collector, data
        
    except Exception as e:
        print(f"❌ 演示失败: {e}")
        return None, None

if __name__ == "__main__":
    collector, data = demo_spotify_collection()

2.2 网易云音乐数据获取

python 复制代码
#!/usr/bin/env python3
"""
网易云音乐数据获取模块
通过网易云音乐API获取用户的听歌数据
"""

import requests
import pandas as pd
import json
import time
from datetime import datetime
from typing import List, Dict, Optional, Any
from dataclasses import dataclass
import os
from pathlib import Path

@dataclass
class NetEaseConfig:
    """网易云音乐配置类"""
    user_id: Optional[str] = None
    phone: Optional[str] = None
    password: Optional[str] = None

class NetEaseDataCollector:
    """
    网易云音乐数据收集器
    通过API获取用户的听歌记录和喜好数据
    """
    
    def __init__(self, config: NetEaseConfig):
        """
        初始化数据收集器
        
        Args:
            config: 网易云音乐配置
        """
        self.config = config
        self.base_url = "http://localhost:3000"  # NetEaseCloudMusicApi服务地址
        self.session = requests.Session()
        self.data_dir = Path("netease_data")
        self.data_dir.mkdir(exist_ok=True)
        
        # 登录获取cookie
        self._login()
    
    def _login(self):
        """
        登录网易云音乐
        """
        try:
            if self.config.phone and self.config.password:
                # 手机号登录
                login_url = f"{self.base_url}/login/cellphone"
                params = {
                    'phone': self.config.phone,
                    'password': self.config.password
                }
                response = self.session.get(login_url, params=params)
                
            elif self.config.user_id:
                # 使用用户ID(需要先通过其他方式获取cookie)
                print("⚠️  用户ID模式需要手动设置cookie")
                return
                
            if response.status_code == 200:
                result = response.json()
                if result.get('code') == 200:
                    print("✅ 网易云音乐登录成功")
                else:
                    print(f"❌ 登录失败: {result.get('message')}")
            else:
                print(f"❌ 登录请求失败: {response.status_code}")
                
        except Exception as e:
            print(f"❌ 登录过程出错: {e}")
    
    def get_recent_plays(self, limit: int = 100) -> List[Dict]:
        """
        获取最近播放记录
        
        Args:
            limit: 获取的记录数量
            
        Returns:
            List[Dict]: 最近播放记录列表
        """
        try:
            url = f"{self.base_url}/user/record"
            params = {
                'uid': self.config.user_id,
                'type': 1  # 1表示所有时间,0表示最近一周
            }
            
            response = self.session.get(url, params=params)
            if response.status_code != 200:
                print(f"❌ 获取播放记录失败: {response.status_code}")
                return []
            
            data = response.json()
            if data['code'] != 200:
                print(f"❌ API返回错误: {data['message']}")
                return []
            
            records = []
            for item in data['allData'][:limit]:
                record = {
                    'play_time': datetime.fromtimestamp(item['playTime'] / 1000),
                    'song_id': item['song']['id'],
                    'song_name': item['song']['name'],
                    'artist_id': item['song']['ar'][0]['id'],
                    'artist_name': item['song']['ar'][0]['name'],
                    'album_id': item['song']['al']['id'],
                    'album_name': item['song']['al']['name'],
                    'duration': item['song']['dt']  # 持续时间(ms)
                }
                records.append(record)
            
            return records
            
        except Exception as e:
            print(f"❌ 获取播放记录出错: {e}")
            return []
    
    def get_user_playlist(self, limit: int = 50) -> List[Dict]:
        """
        获取用户歌单
        
        Args:
            limit: 获取的歌单数量
            
        Returns:
            List[Dict]: 用户歌单列表
        """
        try:
            url = f"{self.base_url}/user/playlist"
            params = {
                'uid': self.config.user_id,
                'limit': limit
            }
            
            response = self.session.get(url, params=params)
            if response.status_code != 200:
                print(f"❌ 获取歌单失败: {response.status_code}")
                return []
            
            data = response.json()
            if data['code'] != 200:
                print(f"❌ API返回错误: {data['message']}")
                return []
            
            playlists = []
            for playlist in data['playlist']:
                playlist_data = {
                    'playlist_id': playlist['id'],
                    'playlist_name': playlist['name'],
                    'create_time': datetime.fromtimestamp(playlist['createTime'] / 1000),
                    'update_time': datetime.fromtimestamp(playlist['updateTime'] / 1000),
                    'track_count': playlist['trackCount'],
                    'play_count': playlist['playCount'],
                    'subscribed_count': playlist['subscribedCount'],
                    'description': playlist.get('description', ''),
                    'tags': playlist.get('tags', [])
                }
                playlists.append(playlist_data)
            
            return playlists
            
        except Exception as e:
            print(f"❌ 获取歌单出错: {e}")
            return []
    
    def get_playlist_detail(self, playlist_id: int) -> List[Dict]:
        """
        获取歌单详情
        
        Args:
            playlist_id: 歌单ID
            
        Returns:
            List[Dict]: 歌单中的歌曲列表
        """
        try:
            url = f"{self.base_url}/playlist/detail"
            params = {
                'id': playlist_id
            }
            
            response = self.session.get(url, params=params)
            if response.status_code != 200:
                print(f"❌ 获取歌单详情失败: {response.status_code}")
                return []
            
            data = response.json()
            if data['code'] != 200:
                print(f"❌ API返回错误: {data['message']}")
                return []
            
            tracks = []
            for track in data['playlist']['tracks']:
                track_data = {
                    'song_id': track['id'],
                    'song_name': track['name'],
                    'artist_id': track['ar'][0]['id'],
                    'artist_name': track['ar'][0]['name'],
                    'album_id': track['al']['id'],
                    'album_name': track['al']['name'],
                    'duration': track['dt'],
                    'popularity': track.get('pop', 0)
                }
                tracks.append(track_data)
            
            return tracks
            
        except Exception as e:
            print(f"❌ 获取歌单详情出错: {e}")
            return []
    
    def get_liked_songs(self, limit: int = 100) -> List[Dict]:
        """
        获取用户喜欢的音乐
        
        Args:
            limit: 获取的歌曲数量
            
        Returns:
            List[Dict]: 喜欢的歌曲列表
        """
        try:
            url = f"{self.base_url}/likelist"
            params = {
                'uid': self.config.user_id
            }
            
            response = self.session.get(url, params=params)
            if response.status_code != 200:
                print(f"❌ 获取喜欢列表失败: {response.status_code}")
                return []
            
            data = response.json()
            if data['code'] != 200:
                print(f"❌ API返回错误: {data['message']}")
                return []
            
            # 获取歌曲详情
            song_ids = data['ids'][:limit]
            if not song_ids:
                return []
            
            # 批量获取歌曲详情
            detail_url = f"{self.base_url}/song/detail"
            params = {'ids': ','.join(map(str, song_ids))}
            
            response = self.session.get(detail_url, params=params)
            if response.status_code != 200:
                return []
            
            detail_data = response.json()
            if detail_data['code'] != 200:
                return []
            
            liked_songs = []
            for song in detail_data['songs']:
                song_data = {
                    'song_id': song['id'],
                    'song_name': song['name'],
                    'artist_name': song['ar'][0]['name'],
                    'album_name': song['al']['name'],
                    'duration': song['dt']
                }
                liked_songs.append(song_data)
            
            return liked_songs
            
        except Exception as e:
            print(f"❌ 获取喜欢歌曲出错: {e}")
            return []
    
    def collect_all_data(self) -> Dict[str, pd.DataFrame]:
        """
        收集所有类型的听歌数据
        
        Returns:
            Dict[str, pd.DataFrame]: 包含所有数据的字典
        """
        print("开始收集网易云音乐听歌数据...")
        
        data_frames = {}
        
        # 收集最近播放
        print("📻 获取最近播放记录...")
        recent_plays = self.get_recent_plays(limit=100)
        if recent_plays:
            data_frames['recent_plays'] = pd.DataFrame(recent_plays)
        
        # 收集用户歌单
        print("🎵 获取用户歌单...")
        playlists = self.get_user_playlist(limit=50)
        if playlists:
            data_frames['playlists'] = pd.DataFrame(playlists)
            
            # 获取前3个歌单的详情
            print("🎶 获取歌单详情...")
            for i, playlist in enumerate(playlists[:3]):
                playlist_id = playlist['playlist_id']
                playlist_name = playlist['playlist_name']
                
                tracks = self.get_playlist_detail(playlist_id)
                if tracks:
                    df = pd.DataFrame(tracks)
                    df['playlist_name'] = playlist_name
                    key = f'playlist_tracks_{i+1}'
                    data_frames[key] = df
        
        # 收集喜欢的歌曲
        print("❤️ 获取喜欢的歌曲...")
        liked_songs = self.get_liked_songs(limit=100)
        if liked_songs:
            data_frames['liked_songs'] = pd.DataFrame(liked_songs)
        
        # 保存数据到文件
        self._save_dataframes(data_frames)
        
        print(f"✅ 数据收集完成! 共收集 {len(data_frames)} 个数据集")
        return data_frames
    
    def _save_dataframes(self, data_frames: Dict[str, pd.DataFrame]):
        """
        保存DataFrame到CSV文件
        
        Args:
            data_frames: 包含DataFrame的字典
        """
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        for name, df in data_frames.items():
            filename = self.data_dir / f"{name}_{timestamp}.csv"
            df.to_csv(filename, index=False, encoding='utf-8')
            print(f"💾 保存: {filename}")

# 演示函数
def demo_netease_collection():
    """演示网易云音乐数据收集"""
    print("网易云音乐数据收集演示")
    print("=" * 50)
    
    # 配置(需要用户提供)
    config = NetEaseConfig(
        user_id=os.getenv('NETEASE_USER_ID'),  # 从环境变量获取
        phone=os.getenv('NETEASE_PHONE'),
        password=os.getenv('NETEASE_PASSWORD')
    )
    
    if not config.user_id and not config.phone:
        print("❌ 请提供用户ID或手机号:")
        print("   export NETEASE_USER_ID=your_user_id")
        print("   或")
        print("   export NETEASE_PHONE=your_phone")
        print("   export NETEASE_PASSWORD=your_password")
        return None, None
    
    try:
        # 创建收集器
        collector = NetEaseDataCollector(config)
        
        # 收集数据
        data = collector.collect_all_data()
        
        # 显示数据统计
        print("\n📊 数据收集统计:")
        for name, df in data.items():
            print(f"  {name}: {len(df)} 条记录")
        
        return collector, data
        
    except Exception as e:
        print(f"❌ 演示失败: {e}")
        return None, None

if __name__ == "__main__":
    collector, data = demo_netease_collection()

3. 数据分析核心引擎

3.1 音乐特征分析

python 复制代码
#!/usr/bin/env python3
"""
音乐数据分析核心引擎
包含各种分析功能和可视化工具
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple
import warnings
from scipy import stats
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import networkx as nx

warnings.filterwarnings('ignore')

class MusicAnalyzer:
    """
    音乐数据分析器
    提供各种音乐数据的分析功能
    """
    
    def __init__(self, data_frames: Dict[str, pd.DataFrame]):
        """
        初始化分析器
        
        Args:
            data_frames: 包含音乐数据的DataFrame字典
        """
        self.data_frames = data_frames
        self.setup_plot_style()
    
    def setup_plot_style(self):
        """设置绘图样式"""
        plt.style.use('seaborn-v0_8')
        sns.set_palette("husl")
        
        # 设置中文字体
        plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
        plt.rcParams['axes.unicode_minus'] = False
    
    def analyze_listening_habits(self) -> Dict[str, Any]:
        """
        分析听歌习惯
        
        Returns:
            Dict[str, Any]: 听歌习惯分析结果
        """
        analysis = {}
        
        # 检查是否有最近播放数据
        if 'recent_tracks' in self.data_frames:
            df = self.data_frames['recent_tracks']
            analysis.update(self._analyze_recent_tracks(df))
        
        if 'recent_plays' in self.data_frames:
            df = self.data_frames['recent_plays']
            analysis.update(self._analyze_recent_plays(df))
        
        return analysis
    
    def _analyze_recent_tracks(self, df: pd.DataFrame) -> Dict[str, Any]:
        """分析Spotify最近播放数据"""
        analysis = {}
        
        # 时间分析
        df['hour'] = df['played_at'].dt.hour
        df['day_of_week'] = df['played_at'].dt.day_name()
        df['date'] = df['played_at'].dt.date
        
        # 基本统计
        analysis['total_tracks'] = len(df)
        analysis['unique_artists'] = df['artist_name'].nunique()
        analysis['unique_tracks'] = df['track_name'].nunique()
        analysis['time_period'] = {
            'start': df['played_at'].min(),
            'end': df['played_at'].max(),
            'days': (df['played_at'].max() - df['played_at'].min()).days
        }
        
        # 时间段分析
        hour_distribution = df['hour'].value_counts().sort_index()
        analysis['hourly_distribution'] = hour_distribution.to_dict()
        
        # 星期分析
        day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
        day_distribution = df['day_of_week'].value_counts().reindex(day_order, fill_value=0)
        analysis['daily_distribution'] = day_distribution.to_dict()
        
        # 最常听艺术家
        top_artists = df['artist_name'].value_counts().head(10)
        analysis['top_artists'] = top_artists.to_dict()
        
        # 最常听歌曲
        top_tracks = df.groupby(['track_name', 'artist_name']).size().sort_values(ascending=False).head(10)
        analysis['top_tracks'] = top_tracks.to_dict()
        
        return analysis
    
    def _analyze_recent_plays(self, df: pd.DataFrame) -> Dict[str, Any]:
        """分析网易云最近播放数据"""
        analysis = {}
        
        # 时间分析
        df['hour'] = df['play_time'].dt.hour
        df['day_of_week'] = df['play_time'].dt.day_name()
        df['date'] = df['play_time'].dt.date
        
        # 基本统计
        analysis['total_plays'] = len(df)
        analysis['unique_artists'] = df['artist_name'].nunique()
        analysis['unique_songs'] = df['song_name'].nunique()
        
        # 时间段分析
        hour_distribution = df['hour'].value_counts().sort_index()
        analysis['hourly_distribution'] = hour_distribution.to_dict()
        
        # 最常听艺术家
        top_artists = df['artist_name'].value_counts().head(10)
        analysis['top_artists'] = top_artists.to_dict()
        
        return analysis
    
    def analyze_music_features(self) -> Dict[str, Any]:
        """
        分析音乐音频特征
        
        Returns:
            Dict[str, Any]: 音频特征分析结果
        """
        analysis = {}
        
        # 检查是否有Spotify音频特征数据
        for key in ['top_tracks_short_term', 'top_tracks_medium_term', 'top_tracks_long_term']:
            if key in self.data_frames:
                df = self.data_frames[key]
                feature_analysis = self._analyze_audio_features(df)
                analysis[key] = feature_analysis
        
        return analysis
    
    def _analyze_audio_features(self, df: pd.DataFrame) -> Dict[str, Any]:
        """分析音频特征"""
        # 音频特征列
        feature_columns = [
            'danceability', 'energy', 'valence', 'tempo',
            'acousticness', 'instrumentalness', 'liveness', 'speechiness'
        ]
        
        # 检查是否存在这些列
        available_features = [col for col in feature_columns if col in df.columns]
        
        if not available_features:
            return {}
        
        analysis = {}
        
        # 基本统计
        for feature in available_features:
            analysis[feature] = {
                'mean': df[feature].mean(),
                'std': df[feature].std(),
                'min': df[feature].min(),
                'max': df[feature].max(),
                'median': df[feature].median()
            }
        
        # 特征相关性
        feature_corr = df[available_features].corr()
        analysis['correlation_matrix'] = feature_corr.to_dict()
        
        # 聚类分析
        if len(available_features) >= 3:
            cluster_analysis = self._cluster_analysis(df[available_features])
            analysis['clusters'] = cluster_analysis
        
        return analysis
    
    def _cluster_analysis(self, features_df: pd.DataFrame) -> Dict[str, Any]:
        """聚类分析"""
        # 标准化特征
        scaler = StandardScaler()
        features_scaled = scaler.fit_transform(features_df)
        
        # 使用肘部法则确定最佳聚类数
        wcss = []
        for i in range(1, 6):
            kmeans = KMeans(n_clusters=i, random_state=42, n_init=10)
            kmeans.fit(features_scaled)
            wcss.append(kmeans.inertia_)
        
        # 选择聚类数(简化:固定为3)
        kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
        clusters = kmeans.fit_predict(features_scaled)
        
        return {
            'cluster_labels': clusters.tolist(),
            'cluster_centers': kmeans.cluster_centers_.tolist(),
            'inertia': kmeans.inertia_
        }
    
    def analyze_artist_network(self) -> Dict[str, Any]:
        """
        分析艺术家关系网络
        
        Returns:
            Dict[str, Any]: 艺术家网络分析结果
        """
        # 收集所有艺术家数据
        all_artists = []
        
        for df_name, df in self.data_frames.items():
            if 'artist_name' in df.columns:
                artists = df['artist_name'].value_counts().to_dict()
                all_artists.append(artists)
        
        if not all_artists:
            return {}
        
        # 合并艺术家数据
        artist_weights = {}
        for artist_dict in all_artists:
            for artist, count in artist_dict.items():
                if artist in artist_weights:
                    artist_weights[artist] += count
                else:
                    artist_weights[artist] = count
        
        # 创建网络图
        G = nx.Graph()
        
        # 添加节点(艺术家)
        for artist, weight in list(artist_weights.items())[:50]:  # 限制数量
            G.add_node(artist, weight=weight)
        
        # 添加边(共同出现关系)
        # 这里简化处理,实际中可以根据歌单、专辑等建立关系
        for df_name, df in self.data_frames.items():
            if 'artist_name' in df.columns:
                artists_in_df = df['artist_name'].unique()
                for i, artist1 in enumerate(artists_in_df):
                    for artist2 in artists_in_df[i+1:]:
                        if artist1 in G and artist2 in G:
                            if G.has_edge(artist1, artist2):
                                G[artist1][artist2]['weight'] += 1
                            else:
                                G.add_edge(artist1, artist2, weight=1)
        
        # 网络分析
        if len(G.nodes) > 0:
            analysis = {
                'number_of_nodes': G.number_of_nodes(),
                'number_of_edges': G.number_of_edges(),
                'density': nx.density(G),
                'average_degree': sum(dict(G.degree()).values()) / G.number_of_nodes(),
                'centrality': dict(nx.degree_centrality(G))
            }
            return analysis
        
        return {}
    
    def generate_visualizations(self, analysis_results: Dict[str, Any]):
        """
        生成可视化图表
        
        Args:
            analysis_results: 分析结果字典
        """
        # 听歌时间分布
        if 'hourly_distribution' in analysis_results.get('listening_habits', {}):
            self._plot_hourly_distribution(analysis_results['listening_habits']['hourly_distribution'])
        
        # 艺术家排行
        if 'top_artists' in analysis_results.get('listening_habits', {}):
            self._plot_top_artists(analysis_results['listening_habits']['top_artists'])
        
        # 音频特征雷达图
        if 'music_features' in analysis_results:
            self._plot_audio_features(analysis_results['music_features'])
    
    def _plot_hourly_distribution(self, hourly_data: Dict[int, int]):
        """绘制小时分布图"""
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))
        
        # 柱状图
        hours = list(hourly_data.keys())
        counts = list(hourly_data.values())
        
        ax1.bar(hours, counts, color='skyblue', edgecolor='navy', alpha=0.7)
        ax1.set_xlabel('小时')
        ax1.set_ylabel('播放次数')
        ax1.set_title('听歌时间分布(按小时)')
        ax1.grid(True, alpha=0.3)
        
        # 极坐标图
        theta = np.linspace(0, 2 * np.pi, 24, endpoint=False)
        radii = [hourly_data.get(i, 0) for i in range(24)]
        
        ax2 = plt.subplot(122, projection='polar')
        ax2.plot(theta, radii, 'o-', linewidth=2)
        ax2.fill(theta, radii, alpha=0.3)
        ax2.set_title('24小时听歌分布', va='bottom')
        
        plt.tight_layout()
        plt.show()
    
    def _plot_top_artists(self, top_artists: Dict[str, int]):
        """绘制顶级艺术家图表"""
        artists = list(top_artists.keys())[:10]
        counts = list(top_artists.values())[:10]
        
        plt.figure(figsize=(12, 8))
        y_pos = np.arange(len(artists))
        
        plt.barh(y_pos, counts, color='lightcoral', edgecolor='darkred', alpha=0.7)
        plt.yticks(y_pos, artists)
        plt.xlabel('播放次数')
        plt.title('最常听的艺术家 Top 10')
        
        # 在条形上添加数值
        for i, v in enumerate(counts):
            plt.text(v + 0.5, i, str(v), va='center')
        
        plt.tight_layout()
        plt.show()
    
    def _plot_audio_features(self, features_analysis: Dict[str, Any]):
        """绘制音频特征雷达图"""
        if not features_analysis:
            return
        
        # 获取第一个时间段的特征
        first_key = next(iter(features_analysis))
        features = features_analysis[first_key]
        
        # 选择要显示的特征
        radar_features = ['danceability', 'energy', 'valence', 'acousticness', 'instrumentalness']
        available_features = [f for f in radar_features if f in features]
        
        if len(available_features) < 3:
            return
        
        # 准备数据
        values = [features[f]['mean'] for f in available_features]
        categories = available_features
        
        # 雷达图
        angles = np.linspace(0, 2 * np.pi, len(categories), endpoint=False).tolist()
        values += values[:1]  # 闭合图形
        angles += angles[:1]
        
        fig, ax = plt.subplots(figsize=(10, 10), subplot_kw=dict(projection='polar'))
        ax.plot(angles, values, 'o-', linewidth=2, label='音频特征')
        ax.fill(angles, values, alpha=0.3)
        
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels(categories)
        ax.set_ylim(0, 1)
        ax.set_title('音乐音频特征雷达图', size=16, y=1.05)
        
        plt.show()

# 演示函数
def demo_music_analysis():
    """演示音乐数据分析"""
    print("音乐数据分析演示")
    print("=" * 50)
    
    # 创建示例数据(实际中应该从文件加载)
    sample_data = create_sample_data()
    
    # 创建分析器
    analyzer = MusicAnalyzer(sample_data)
    
    # 执行分析
    print("🔍 分析听歌习惯...")
    listening_analysis = analyzer.analyze_listening_habits()
    
    print("🎵 分析音乐特征...")
    feature_analysis = analyzer.analyze_music_features()
    
    print("🌐 分析艺术家网络...")
    network_analysis = analyzer.analyze_artist_network()
    
    # 合并分析结果
    all_analysis = {
        'listening_habits': listening_analysis,
        'music_features': feature_analysis,
        'artist_network': network_analysis
    }
    
    # 显示分析结果
    print("\n📊 分析结果摘要:")
    if listening_analysis:
        print(f"  总播放次数: {listening_analysis.get('total_tracks', listening_analysis.get('total_plays', 0))}")
        print(f"  独特艺术家: {listening_analysis.get('unique_artists', 0)}")
    
    # 生成可视化
    print("\n🎨 生成可视化图表...")
    analyzer.generate_visualizations(all_analysis)
    
    return analyzer, all_analysis

def create_sample_data() -> Dict[str, pd.DataFrame]:
    """创建示例数据用于演示"""
    # 最近播放数据
    recent_data = {
        'played_at': pd.date_range('2024-01-01', periods=100, freq='H'),
        'track_name': ['Song ' + str(i) for i in range(100)],
        'artist_name': ['Artist ' + str(i % 20) for i in range(100)],
        'duration_ms': np.random.randint(180000, 300000, 100)
    }
    
    # 音频特征数据
    audio_data = {
        'track_name': ['Track ' + str(i) for i in range(50)],
        'artist_name': ['Artist ' + str(i % 15) for i in range(50)],
        'danceability': np.random.uniform(0, 1, 50),
        'energy': np.random.uniform(0, 1, 50),
        'valence': np.random.uniform(0, 1, 50),
        'tempo': np.random.uniform(60, 180, 50),
        'acousticness': np.random.uniform(0, 1, 50),
        'instrumentalness': np.random.uniform(0, 1, 50)
    }
    
    return {
        'recent_tracks': pd.DataFrame(recent_data),
        'top_tracks_medium_term': pd.DataFrame(audio_data)
    }

if __name__ == "__main__":
    analyzer, results = demo_music_analysis()

4. 高级分析与机器学习

4.1 情绪分析与模式识别

python 复制代码
#!/usr/bin/env python3
"""
高级音乐分析模块
包含情绪分析、模式识别和预测功能
"""

import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
from typing import Dict, List, Tuple, Optional
import warnings

warnings.filterwarnings('ignore')

class AdvancedMusicAnalyzer:
    """
    高级音乐分析器
    提供情绪分析、聚类分析和预测功能
    """
    
    def __init__(self, data_frames: Dict[str, pd.DataFrame]):
        self.data_frames = data_frames
        self.setup_plot_style()
    
    def setup_plot_style(self):
        """设置绘图样式"""
        plt.style.use('seaborn-v0_8')
        sns.set_palette("husl")
        plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
        plt.rcParams['axes.unicode_minus'] = False
    
    def mood_analysis(self) -> Dict[str, Any]:
        """
        基于音频特征的情绪分析
        
        Returns:
            Dict[str, Any]: 情绪分析结果
        """
        # 收集所有音频特征数据
        audio_features = []
        track_info = []
        
        for key, df in self.data_frames.items():
            if any(feat in df.columns for feat in ['valence', 'energy', 'danceability']):
                feature_cols = ['valence', 'energy', 'danceability', 'acousticness', 'instrumentalness']
                available_cols = [col for col in feature_cols if col in df.columns]
                
                if available_cols:
                    features = df[available_cols].copy()
                    features = features.dropna()
                    
                    if len(features) > 0:
                        audio_features.append(features)
                        track_info.extend(zip(df['track_name'].iloc[:len(features)], 
                                            df['artist_name'].iloc[:len(features)]))
        
        if not audio_features:
            return {}
        
        # 合并所有特征
        all_features = pd.concat(audio_features, ignore_index=True)
        
        # 情绪分类基于valence和energy
        # 根据Russell的情感环状模型
        moods = []
        for _, row in all_features.iterrows():
            valence = row.get('valence', 0.5)
            energy = row.get('energy', 0.5)
            
            if valence > 0.6 and energy > 0.6:
                mood = "兴奋快乐"
            elif valence > 0.6 and energy <= 0.6:
                mood = "平静愉悦"
            elif valence <= 0.6 and energy > 0.6:
                mood = "紧张焦虑"
            elif valence <= 0.4 and energy <= 0.4:
                mood = "悲伤忧郁"
            else:
                mood = "中性平静"
            
            moods.append(mood)
        
        all_features['mood'] = moods
        
        # 情绪分布统计
        mood_distribution = all_features['mood'].value_counts().to_dict()
        
        # 为每个曲目添加情绪标签
        mood_tracks = []
        for i, (track, artist) in enumerate(track_info[:len(all_features)]):
            mood_tracks.append({
                'track': track,
                'artist': artist,
                'mood': moods[i],
                'valence': all_features.iloc[i].get('valence', 0),
                'energy': all_features.iloc[i].get('energy', 0)
            })
        
        return {
            'mood_distribution': mood_distribution,
            'mood_tracks': mood_tracks,
            'total_analyzed': len(all_features)
        }
    
    def listening_pattern_clustering(self) -> Dict[str, Any]:
        """
        听歌模式聚类分析
        
        Returns:
            Dict[str, Any]: 聚类分析结果
        """
        # 构建听歌模式特征矩阵
        pattern_data = []
        
        # 分析时间模式
        for key, df in self.data_frames.items():
            if 'played_at' in df.columns or 'play_time' in df.columns:
                time_col = 'played_at' if 'played_at' in df.columns else 'play_time'
                
                # 提取时间特征
                df = df.copy()
                df[time_col] = pd.to_datetime(df[time_col])
                df['hour'] = df[time_col].dt.hour
                df['day_of_week'] = df[time_col].dt.dayofweek
                df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)
                
                # 按日期聚合
                daily_patterns = df.groupby(df[time_col].dt.date).agg({
                    'hour': ['mean', 'std', 'count'],
                    'is_weekend': 'first'
                }).fillna(0)
                
                daily_patterns.columns = ['hour_mean', 'hour_std', 'play_count', 'is_weekend']
                pattern_data.append(daily_patterns)
        
        if not pattern_data:
            return {}
        
        # 合并模式数据
        all_patterns = pd.concat(pattern_data, ignore_index=True)
        
        # 标准化特征
        feature_cols = ['hour_mean', 'hour_std', 'play_count']
        scaler = StandardScaler()
        features_scaled = scaler.fit_transform(all_patterns[feature_cols])
        
        # K-means聚类
        kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
        clusters = kmeans.fit_predict(features_scaled)
        
        all_patterns['cluster'] = clusters
        
        # 分析每个簇的特征
        cluster_profiles = {}
        for cluster_id in range(3):
            cluster_data = all_patterns[all_patterns['cluster'] == cluster_id]
            profile = {
                'size': len(cluster_data),
                'avg_play_count': cluster_data['play_count'].mean(),
                'avg_hour': cluster_data['hour_mean'].mean(),
                'weekend_ratio': cluster_data['is_weekend'].mean()
            }
            cluster_profiles[f'cluster_{cluster_id}'] = profile
        
        # 给每个簇命名
        cluster_names = {}
        for cluster_id, profile in cluster_profiles.items():
            avg_hour = profile['avg_hour']
            play_count = profile['avg_play_count']
            weekend_ratio = profile['weekend_ratio']
            
            if avg_hour < 12:
                time_of_day = "早晨"
            elif avg_hour < 18:
                time_of_day = "下午"
            else:
                time_of_day = "夜晚"
            
            if play_count > all_patterns['play_count'].mean():
                intensity = "重度"
            else:
                intensity = "轻度"
            
            if weekend_ratio > 0.5:
                pattern_type = "周末"
            else:
                pattern_type = "工作日"
            
            cluster_names[cluster_id] = f"{intensity}{time_of_day}{pattern_type}听歌者"
        
        return {
            'clusters': cluster_profiles,
            'cluster_names': cluster_names,
            'total_patterns': len(all_patterns)
        }
    
    def genre_analysis(self) -> Dict[str, Any]:
        """
        音乐类型分析(基于艺术家流派)
        
        Returns:
            Dict[str, Any]: 类型分析结果
        """
        # 收集艺术家数据
        artist_genres = {}
        
        for key, df in self.data_frames.items():
            if 'artist_name' in df.columns and 'genres' in df.columns:
                for _, row in df.iterrows():
                    artist = row['artist_name']
                    genres = row['genres']
                    if isinstance(genres, list) and genres:
                        if artist not in artist_genres:
                            artist_genres[artist] = []
                        artist_genres[artist].extend(genres)
        
        # 如果没有流派数据,尝试从艺术家名字推断
        if not artist_genres:
            return self._infer_genres_from_artists()
        
        # 统计流派分布
        all_genres = []
        for genres in artist_genres.values():
            all_genres.extend(genres)
        
        if not all_genres:
            return {}
        
        genre_counts = pd.Series(all_genres).value_counts().head(10)
        
        # 流派情感分析(简化版)
        genre_moods = {}
        mood_mapping = {
            'rock': 'energetic', 'pop': 'happy', 'jazz': 'relaxed',
            'classical': 'calm', 'hip hop': 'confident', 'electronic': 'energetic',
            'r&b': 'romantic', 'country': 'nostalgic', 'metal': 'intense',
            'folk': 'thoughtful'
        }
        
        for genre in genre_counts.index:
            genre_moods[genre] = mood_mapping.get(genre, 'neutral')
        
        return {
            'top_genres': genre_counts.to_dict(),
            'genre_moods': genre_moods,
            'total_artists_analyzed': len(artist_genres)
        }
    
    def _infer_genres_from_artists(self) -> Dict[str, Any]:
        """从艺术家名字推断流派(简化实现)"""
        # 这是一个简化的实现,实际中应该使用更复杂的NLP方法
        artist_counts = {}
        
        for key, df in self.data_frames.items():
            if 'artist_name' in df.columns:
                artists = df['artist_name'].value_counts().to_dict()
                for artist, count in artists.items():
                    if artist in artist_counts:
                        artist_counts[artist] += count
                    else:
                        artist_counts[artist] = count
        
        # 基于已知艺术家推断流派(简化)
        known_genres = {
            'Taylor Swift': 'pop', 'Ed Sheeran': 'pop', 'Drake': 'hip hop',
            'Beyoncé': 'r&b', 'Mozart': 'classical', 'Beatles': 'rock',
            'BTS': 'k-pop', 'Billie Eilish': 'alternative', 'The Weeknd': 'r&b'
        }
        
        genre_counts = {}
        for artist, count in list(artist_counts.items())[:20]:  # 只看前20
            for known_artist, genre in known_genres.items():
                if known_artist.lower() in artist.lower():
                    if genre in genre_counts:
                        genre_counts[genre] += count
                    else:
                        genre_counts[genre] = count
                    break
        
        return {
            'inferred_genres': genre_counts,
            'total_artists': len(artist_counts),
            'note': '流派基于艺术家名字推断,可能不准确'
        }
    
    def seasonal_analysis(self) -> Dict[str, Any]:
        """
        季节性听歌模式分析
        
        Returns:
            Dict[str, Any]: 季节性分析结果
        """
        seasonal_data = []
        
        for key, df in self.data_frames.items():
            if 'played_at' in df.columns or 'play_time' in df.columns:
                time_col = 'played_at' if 'played_at' in df.columns else 'play_time'
                df = df.copy()
                df[time_col] = pd.to_datetime(df[time_col])
                
                # 提取季节信息
                df['month'] = df[time_col].dt.month
                df['season'] = df['month'].apply(self._get_season)
                
                seasonal_counts = df['season'].value_counts().to_dict()
                seasonal_data.append(seasonal_counts)
        
        if not seasonal_data:
            return {}
        
        # 合并季节性数据
        all_seasons = {}
        for season_dict in seasonal_data:
            for season, count in season_dict.items():
                if season in all_seasons:
                    all_seasons[season] += count
                else:
                    all_seasons[season] = count
        
        return {
            'seasonal_distribution': all_seasons,
            'most_active_season': max(all_seasons, key=all_seasons.get) if all_seasons else None
        }
    
    def _get_season(self, month: int) -> str:
        """根据月份获取季节"""
        if month in [12, 1, 2]:
            return "冬季"
        elif month in [3, 4, 5]:
            return "春季"
        elif month in [6, 7, 8]:
            return "夏季"
        else:
            return "秋季"
    
    def generate_advanced_visualizations(self, analysis_results: Dict[str, Any]):
        """
        生成高级分析可视化
        
        Args:
            analysis_results: 高级分析结果
        """
        # 情绪分析可视化
        if 'mood_analysis' in analysis_results:
            self._plot_mood_analysis(analysis_results['mood_analysis'])
        
        # 聚类分析可视化
        if 'pattern_clustering' in analysis_results:
            self._plot_pattern_clustering(analysis_results['pattern_clustering'])
        
        # 流派分析可视化
        if 'genre_analysis' in analysis_results:
            self._plot_genre_analysis(analysis_results['genre_analysis'])
    
    def _plot_mood_analysis(self, mood_analysis: Dict[str, Any]):
        """绘制情绪分析图"""
        if 'mood_distribution' not in mood_analysis:
            return
        
        mood_data = mood_analysis['mood_distribution']
        
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
        
        # 饼图
        ax1.pie(mood_data.values(), labels=mood_data.keys(), autopct='%1.1f%%', startangle=90)
        ax1.set_title('情绪分布')
        
        # 散点图(valence vs energy)
        if 'mood_tracks' in mood_analysis:
            tracks = mood_analysis['mood_tracks']
            if tracks:
                valence = [t['valence'] for t in tracks]
                energy = [t['energy'] for t in tracks]
                moods = [t['mood'] for t in tracks]
                
                # 为每种情绪分配颜色
                mood_colors = {
                    '兴奋快乐': 'red',
                    '平静愉悦': 'green', 
                    '紧张焦虑': 'orange',
                    '悲伤忧郁': 'blue',
                    '中性平静': 'gray'
                }
                
                colors = [mood_colors.get(mood, 'black') for mood in moods]
                
                ax2.scatter(valence, energy, c=colors, alpha=0.6)
                ax2.set_xlabel('Valence(愉悦度)')
                ax2.set_ylabel('Energy(能量)')
                ax2.set_title('情绪分布(Valence vs Energy)')
                ax2.grid(True, alpha=0.3)
        
        plt.tight_layout()
        plt.show()
    
    def _plot_pattern_clustering(self, clustering: Dict[str, Any]):
        """绘制聚类分析图"""
        if 'clusters' not in clustering:
            return
        
        clusters = clustering['clusters']
        
        # 创建雷达图显示聚类特征
        features = ['avg_play_count', 'avg_hour', 'weekend_ratio']
        cluster_ids = list(clusters.keys())
        
        fig, ax = plt.subplots(figsize=(10, 8), subplot_kw=dict(projection='polar'))
        
        # 标准化特征值用于雷达图
        for cluster_id in cluster_ids:
            profile = clusters[cluster_id]
            values = [
                profile['avg_play_count'] / 10,  # 简化标准化
                profile['avg_hour'] / 24,
                profile['weekend_ratio']
            ]
            
            angles = np.linspace(0, 2 * np.pi, len(features), endpoint=False).tolist()
            values += values[:1]  # 闭合图形
            angles += angles[:1]
            
            ax.plot(angles, values, 'o-', linewidth=2, label=clustering['cluster_names'].get(int(cluster_id.split('_')[1]), cluster_id))
            ax.fill(angles, values, alpha=0.1)
        
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels(['播放频率', '平均时间', '周末比例'])
        ax.set_title('听歌模式聚类分析')
        ax.legend()
        
        plt.show()
    
    def _plot_genre_analysis(self, genre_analysis: Dict[str, Any]):
        """绘制流派分析图"""
        if 'top_genres' not in genre_analysis and 'inferred_genres' not in genre_analysis:
            return
        
        genres_data = genre_analysis.get('top_genres', genre_analysis.get('inferred_genres', {}))
        
        if not genres_data:
            return
        
        plt.figure(figsize=(12, 8))
        genres = list(genres_data.keys())
        counts = list(genres_data.values())
        
        # 水平条形图
        y_pos = np.arange(len(genres))
        bars = plt.barh(y_pos, counts, color='lightseagreen', alpha=0.7)
        
        plt.yticks(y_pos, genres)
        plt.xlabel('出现次数')
        plt.title('音乐流派分布')
        
        # 添加数值标签
        for bar, count in zip(bars, counts):
            plt.text(bar.get_width() + 0.5, bar.get_y() + bar.get_height()/2, 
                    str(count), va='center')
        
        plt.tight_layout()
        plt.show()

# 演示函数
def demo_advanced_analysis():
    """演示高级分析功能"""
    print("高级音乐分析演示")
    print("=" * 50)
    
    # 创建示例数据
    sample_data = create_advanced_sample_data()
    
    # 创建高级分析器
    analyzer = AdvancedMusicAnalyzer(sample_data)
    
    # 执行各种分析
    print("😊 进行情绪分析...")
    mood_analysis = analyzer.mood_analysis()
    
    print("🔍 进行模式聚类...")
    pattern_analysis = analyzer.listening_pattern_clustering()
    
    print("🎵 进行流派分析...")
    genre_analysis = analyzer.genre_analysis()
    
    print("🌦️ 进行季节性分析...")
    seasonal_analysis = analyzer.seasonal_analysis()
    
    # 合并结果
    all_analysis = {
        'mood_analysis': mood_analysis,
        'pattern_clustering': pattern_analysis,
        'genre_analysis': genre_analysis,
        'seasonal_analysis': seasonal_analysis
    }
    
    # 显示结果摘要
    print("\n📊 高级分析结果摘要:")
    if mood_analysis:
        print(f"  情绪分析: 分析了 {mood_analysis.get('total_analyzed', 0)} 首歌曲")
        print(f"  主要情绪: {list(mood_analysis.get('mood_distribution', {}).keys())[:3]}")
    
    if pattern_analysis:
        print(f"  听歌模式: 发现了 {len(pattern_analysis.get('clusters', {}))} 种模式")
    
    # 生成可视化
    print("\n🎨 生成高级可视化...")
    analyzer.generate_advanced_visualizations(all_analysis)
    
    return analyzer, all_analysis

def create_advanced_sample_data() -> Dict[str, pd.DataFrame]:
    """创建高级分析示例数据"""
    # 创建包含音频特征的数据
    np.random.seed(42)
    
    audio_data = {
        'track_name': [f'Track_{i}' for i in range(100)],
        'artist_name': [f'Artist_{i % 20}' for i in range(100)],
        'valence': np.random.beta(2, 2, 100),  # 偏向中性
        'energy': np.random.beta(2, 3, 100),   # 偏向低能量
        'danceability': np.random.beta(3, 2, 100),  # 偏舞蹈性
        'acousticness': np.random.beta(1, 4, 100),  # 偏非原声
        'instrumentalness': np.random.beta(1, 5, 100),  # 偏非器乐
        'genres': [['pop', 'rock'] if i % 3 == 0 else ['electronic'] if i % 3 == 1 else ['jazz'] for i in range(100)]
    }
    
    # 创建时间模式数据
    dates = pd.date_range('2024-01-01', '2024-06-01', freq='D')
    time_data = {
        'played_at': np.random.choice(dates, 200),
        'track_name': [f'Song_{i}' for i in range(200)],
        'artist_name': [f'Artist_{i % 25}' for i in range(200)]
    }
    
    return {
        'audio_features': pd.DataFrame(audio_data),
        'recent_plays': pd.DataFrame(time_data)
    }

if __name__ == "__main__":
    analyzer, results = demo_advanced_analysis()

5. 完整应用集成

5.1 主应用和报告生成

python 复制代码
#!/usr/bin/env python3
"""
音乐数据分析完整应用
集成数据收集、分析和报告生成
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
import json
from pathlib import Path
from typing import Dict, List, Optional
import warnings

warnings.filterwarnings('ignore')

# 导入各个模块
from spotify_collector import SpotifyDataCollector, setup_spotify_config
from netease_collector import NetEaseDataCollector, NetEaseConfig
from music_analyzer import MusicAnalyzer
from advanced_analyzer import AdvancedMusicAnalyzer

class MusicAnalysisApp:
    """
    音乐数据分析完整应用
    集成数据收集、分析和报告生成
    """
    
    def __init__(self):
        self.data_frames = {}
        self.analysis_results = {}
        self.report_data = {}
        
    def collect_spotify_data(self) -> bool:
        """
        收集Spotify数据
        
        Returns:
            bool: 是否成功收集
        """
        try:
            print("🎵 开始收集Spotify数据...")
            config = setup_spotify_config()
            collector = SpotifyDataCollector(config)
            self.data_frames.update(collector.collect_all_data())
            return True
        except Exception as e:
            print(f"❌ Spotify数据收集失败: {e}")
            return False
    
    def collect_netease_data(self) -> bool:
        """
        收集网易云音乐数据
        
        Returns:
            bool: 是否成功收集
        """
        try:
            print("🎵 开始收集网易云音乐数据...")
            config = NetEaseConfig(
                user_id='your_user_id'  # 需要用户提供
            )
            collector = NetEaseDataCollector(config)
            self.data_frames.update(collector.collect_all_data())
            return True
        except Exception as e:
            print(f"❌ 网易云音乐数据收集失败: {e}")
            return False
    
    def run_analysis(self):
        """运行完整分析流程"""
        print("\n🔍 开始音乐数据分析...")
        
        # 基础分析
        print("📊 进行基础分析...")
        basic_analyzer = MusicAnalyzer(self.data_frames)
        basic_analysis = basic_analyzer.analyze_listening_habits()
        feature_analysis = basic_analyzer.analyze_music_features()
        
        self.analysis_results['basic'] = {
            'listening_habits': basic_analysis,
            'music_features': feature_analysis
        }
        
        # 高级分析
        print("🎯 进行高级分析...")
        advanced_analyzer = AdvancedMusicAnalyzer(self.data_frames)
        mood_analysis = advanced_analyzer.mood_analysis()
        pattern_analysis = advanced_analyzer.listening_pattern_clustering()
        genre_analysis = advanced_analyzer.genre_analysis()
        seasonal_analysis = advanced_analyzer.seasonal_analysis()
        
        self.analysis_results['advanced'] = {
            'mood_analysis': mood_analysis,
            'pattern_clustering': pattern_analysis,
            'genre_analysis': genre_analysis,
            'seasonal_analysis': seasonal_analysis
        }
        
        print("✅ 分析完成!")
    
    def generate_report(self):
        """生成分析报告"""
        print("\n📄 生成分析报告...")
        
        report = {
            'generated_at': datetime.now().isoformat(),
            'data_summary': self._get_data_summary(),
            'key_insights': self._extract_key_insights(),
            'recommendations': self._generate_recommendations()
        }
        
        # 保存报告
        self._save_report(report)
        self.report_data = report
        
        print("✅ 报告生成完成!")
        return report
    
    def _get_data_summary(self) -> Dict[str, Any]:
        """获取数据摘要"""
        summary = {
            'total_datasets': len(self.data_frames),
            'dataset_names': list(self.data_frames.keys()),
            'total_records': sum(len(df) for df in self.data_frames.values())
        }
        
        # 添加各个数据集的统计
        for name, df in self.data_frames.items():
            summary[f'{name}_records'] = len(df)
            if 'artist_name' in df.columns:
                summary[f'{name}_unique_artists'] = df['artist_name'].nunique()
            if 'track_name' in df.columns:
                summary[f'{name}_unique_tracks'] = df['track_name'].nunique()
        
        return summary
    
    def _extract_key_insights(self) -> List[str]:
        """提取关键洞察"""
        insights = []
        
        basic = self.analysis_results.get('basic', {})
        advanced = self.analysis_results.get('advanced', {})
        
        # 从基础分析提取洞察
        if 'listening_habits' in basic:
            habits = basic['listening_habits']
            
            if 'top_artists' in habits:
                top_artist = list(habits['top_artists'].keys())[0]
                insights.append(f"🎤 你最常听的艺术家是: {top_artist}")
            
            if 'hourly_distribution' in habits:
                peak_hour = max(habits['hourly_distribution'], key=habits['hourly_distribution'].get)
                insights.append(f"⏰ 你的听歌高峰时段是: {peak_hour}点")
        
        # 从高级分析提取洞察
        if 'mood_analysis' in advanced:
            mood_data = advanced['mood_analysis']
            if 'mood_distribution' in mood_data:
                top_mood = max(mood_data['mood_distribution'], key=mood_data['mood_distribution'].get)
                insights.append(f"😊 你的主要听歌情绪是: {top_mood}")
        
        if 'pattern_clustering' in advanced:
            pattern_data = advanced['pattern_clustering']
            if 'cluster_names' in pattern_data:
                main_pattern = list(pattern_data['cluster_names'].values())[0]
                insights.append(f"📊 你的主要听歌模式: {main_pattern}")
        
        if 'genre_analysis' in advanced:
            genre_data = advanced['genre_analysis']
            if 'top_genres' in genre_data:
                top_genre = list(genre_data['top_genres'].keys())[0]
                insights.append(f"🎵 你最喜欢的音乐类型是: {top_genre}")
            elif 'inferred_genres' in genre_data:
                top_genre = list(genre_data['inferred_genres'].keys())[0]
                insights.append(f"🎵 你可能喜欢的音乐类型是: {top_genre}")
        
        return insights
    
    def _generate_recommendations(self) -> List[str]:
        """生成个性化推荐"""
        recommendations = []
        
        basic = self.analysis_results.get('basic', {})
        advanced = self.analysis_results.get('advanced', {})
        
        # 基于艺术家推荐
        if 'listening_habits' in basic and 'top_artists' in basic['listening_habits']:
            top_artists = list(basic['listening_habits']['top_artists'].keys())[:3]
            recommendations.append(f"🎶 基于你喜欢的艺术家 {', '.join(top_artists)},可以探索相似风格的音乐")
        
        # 基于情绪推荐
        if 'mood_analysis' in advanced:
            mood_data = advanced['mood_analysis']
            if 'mood_distribution' in mood_data:
                moods = list(mood_data['mood_distribution'].keys())
                if '悲伤忧郁' in moods:
                    recommendations.append("🌞 发现你有时听悲伤的音乐,建议尝试一些积极向上的歌曲来调节心情")
                if '兴奋快乐' in moods:
                    recommendations.append("💃 你很喜欢快乐的音乐!继续保持这种积极的听歌习惯")
        
        # 基于时间模式推荐
        if 'pattern_clustering' in advanced:
            pattern_data = advanced['pattern_clustering']
            if 'clusters' in pattern_data:
                clusters = pattern_data['clusters']
                for cluster_id, profile in clusters.items():
                    if profile['avg_hour'] < 8:
                        recommendations.append("🌅 早晨听歌是个好习惯!建议创建专门的晨间歌单")
                    elif profile['avg_hour'] > 22:
                        recommendations.append("🌙 晚上听歌有助于放松,可以尝试一些轻柔的睡眠音乐")
        
        # 基于流派推荐
        if 'genre_analysis' in advanced:
            genre_data = advanced['genre_analysis']
            if 'top_genres' in genre_data:
                genres = list(genre_data['top_genres'].keys())
                if 'rock' in genres:
                    recommendations.append("🎸 作为摇滚爱好者,你可能也会喜欢经典摇滚或独立摇滚")
                if 'pop' in genres:
                    recommendations.append("🌟 流行音乐爱好者!可以关注最新的流行榜单和新兴艺术家")
        
        return recommendations
    
    def _save_report(self, report: Dict[str, Any]):
        """保存报告到文件"""
        report_dir = Path("music_reports")
        report_dir.mkdir(exist_ok=True)
        
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        # 保存JSON报告
        json_file = report_dir / f"music_analysis_report_{timestamp}.json"
        with open(json_file, 'w', encoding='utf-8') as f:
            json.dump(report, f, indent=2, ensure_ascii=False)
        
        # 保存文本报告
        txt_file = report_dir / f"music_analysis_report_{timestamp}.txt"
        with open(txt_file, 'w', encoding='utf-8') as f:
            f.write(self._format_text_report(report))
        
        print(f"💾 报告已保存: {json_file}")
        print(f"💾 报告已保存: {txt_file}")
    
    def _format_text_report(self, report: Dict[str, Any]) -> str:
        """格式化文本报告"""
        lines = []
        lines.append("=" * 60)
        lines.append("🎵 个人音乐分析报告")
        lines.append("=" * 60)
        lines.append(f"生成时间: {report['generated_at']}")
        lines.append("")
        
        # 数据摘要
        lines.append("📊 数据摘要")
        lines.append("-" * 30)
        summary = report['data_summary']
        lines.append(f"分析数据集: {summary['total_datasets']} 个")
        lines.append(f"总记录数: {summary['total_records']} 条")
        lines.append("")
        
        # 关键洞察
        lines.append("🔍 关键洞察")
        lines.append("-" * 30)
        for insight in report['key_insights']:
            lines.append(f"• {insight}")
        lines.append("")
        
        # 个性化推荐
        lines.append("💡 个性化推荐")
        lines.append("-" * 30)
        for recommendation in report['recommendations']:
            lines.append(f"• {recommendation}")
        lines.append("")
        
        lines.append("=" * 60)
        lines.append("感谢使用音乐分析工具!")
        lines.append("=" * 60)
        
        return '\n'.join(lines)
    
    def generate_visualizations(self):
        """生成所有可视化图表"""
        print("\n🎨 生成可视化图表...")
        
        # 基础分析可视化
        basic_analyzer = MusicAnalyzer(self.data_frames)
        basic_analyzer.generate_visualizations(self.analysis_results.get('basic', {}))
        
        # 高级分析可视化
        advanced_analyzer = AdvancedMusicAnalyzer(self.data_frames)
        advanced_analyzer.generate_advanced_visualizations(self.analysis_results.get('advanced', {}))
    
    def run_complete_analysis(self):
        """运行完整分析流程"""
        print("🚀 开始完整的音乐数据分析流程")
        print("=" * 60)
        
        # 数据收集
        spotify_success = self.collect_spotify_data()
        netease_success = self.collect_netease_data()
        
        if not spotify_success and not netease_success:
            print("❌ 没有成功收集到任何数据,无法进行分析")
            return
        
        # 数据分析
        self.run_analysis()
        
        # 报告生成
        report = self.generate_report()
        
        # 可视化
        self.generate_visualizations()
        
        # 显示报告摘要
        self._display_report_summary(report)
        
        print("\n🎉 分析流程完成!")
    
    def _display_report_summary(self, report: Dict[str, Any]):
        """显示报告摘要"""
        print("\n" + "=" * 60)
        print("📋 分析报告摘要")
        print("=" * 60)
        
        print("\n🔍 关键发现:")
        for insight in report['key_insights']:
            print(f"  • {insight}")
        
        print("\n💡 给你的建议:")
        for recommendation in report['recommendations']:
            print(f"  • {recommendation}")

# 演示函数
def demo_complete_analysis():
    """演示完整分析流程"""
    print("音乐数据分析完整演示")
    print("=" * 60)
    
    # 创建应用实例
    app = MusicAnalysisApp()
    
    # 使用示例数据运行分析(实际中应该收集真实数据)
    print("📝 使用示例数据进行演示...")
    
    # 创建示例数据
    sample_data = create_demo_sample_data()
    app.data_frames = sample_data
    
    # 运行分析
    app.run_analysis()
    
    # 生成报告
    report = app.generate_report()
    
    # 生成可视化
    app.generate_visualizations()
    
    return app, report

def create_demo_sample_data() -> Dict[str, pd.DataFrame]:
    """创建演示用示例数据"""
    import numpy as np
    from datetime import datetime, timedelta
    
    # 最近播放数据
    dates = [datetime.now() - timedelta(hours=i) for i in range(100)]
    recent_data = {
        'played_at': dates,
        'track_name': [f'Demo Track {i}' for i in range(100)],
        'artist_name': [f'Demo Artist {i % 15}' for i in range(100)],
        'album_name': [f'Demo Album {i % 10}' for i in range(100)],
        'duration_ms': np.random.randint(180000, 300000, 100)
    }
    
    # 音频特征数据
    audio_data = {
        'track_name': [f'Featured Track {i}' for i in range(50)],
        'artist_name': [f'Featured Artist {i % 12}' for i in range(50)],
        'danceability': np.random.uniform(0.3, 0.9, 50),
        'energy': np.random.uniform(0.2, 0.95, 50),
        'valence': np.random.uniform(0.1, 0.9, 50),
        'tempo': np.random.uniform(60, 180, 50),
        'acousticness': np.random.uniform(0, 0.8, 50),
        'instrumentalness': np.random.uniform(0, 0.6, 50),
        'genres': [['pop', 'rock'] if i % 2 == 0 else ['electronic'] for i in range(50)]
    }
    
    return {
        'recent_tracks': pd.DataFrame(recent_data),
        'top_tracks_medium_term': pd.DataFrame(audio_data)
    }

if __name__ == "__main__":
    # 演示完整分析
    app, report = demo_complete_analysis()
    
    # 显示使用说明
    print("\n" + "=" * 60)
    print("💡 使用说明")
    print("=" * 60)
    print("要使用真实数据进行分析:")
    print("1. 设置Spotify API凭据")
    print("   export SPOTIFY_CLIENT_ID=your_client_id")
    print("   export SPOTIFY_CLIENT_SECRET=your_client_secret")
    print("2. 运行: app.collect_spotify_data()")
    print("3. 运行: app.run_complete_analysis()")

6. 总结

6.1 项目成果

通过本文,我们构建了一个完整的音乐数据分析系统:

✅ 数据收集能力
  • 多平台支持:Spotify和网易云音乐数据获取
  • 完整数据覆盖:播放历史、音频特征、用户喜好
  • 数据持久化:本地CSV文件存储
✅ 分析功能
  • 听歌习惯分析:时间模式、艺术家偏好、歌曲排行
  • 音频特征分析:情绪识别、音乐特性聚类
  • 高级模式识别:季节性模式、听歌行为分类
  • 个性化洞察:基于数据的音乐品味分析
✅ 可视化与报告
  • 丰富图表:时间分布、情绪分析、聚类可视化
  • 个性化报告:关键洞察和音乐推荐
  • 多种格式:JSON和文本报告输出

6.2 技术亮点

python 复制代码
# 技术架构亮点
technical_achievements = {
    "模块化设计": "清晰的数据流和分析管道",
    "API集成": "完整的Spotify和网易云音乐API支持", 
    "机器学习": "聚类分析、情绪识别、模式发现",
    "数据可视化": "多维度的图表和洞察展示",
    "生产就绪": "错误处理、配置管理、报告生成"
}

6.3 数学与算法原理

在音乐数据分析中,我们应用了重要的数学和机器学习原理:

情绪分析模型

基于Russell的情感环状模型,将音频特征映射到情感空间:

情绪 = f ( valence , energy ) \text{情绪} = f(\text{valence}, \text{energy}) 情绪=f(valence,energy)

其中valence表示愉悦度,energy表示能量水平。

聚类分析

使用K-means算法进行听歌模式聚类:

min ⁡ ∑ i = 1 k ∑ x ∈ C i ∥ x − μ i ∥ 2 \min \sum_{i=1}^{k} \sum_{x \in C_i} \lVert x - \mu_i \rVert^2 mini=1∑kx∈Ci∑∥x−μi∥2

其中 C i C_i Ci是第i个簇, μ i \mu_i μi是簇中心。

特征相关性分析

使用Pearson相关系数分析音频特征之间的关系:

r = ∑ ( x i − x ˉ ) ( y i − y ˉ ) ∑ ( x i − x ˉ ) 2 ∑ ( y i − y ˉ ) 2 r = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum (x_i - \bar{x})^2 \sum (y_i - \bar{y})^2}} r=∑(xi−xˉ)2∑(yi−yˉ)2 ∑(xi−xˉ)(yi−yˉ)

6.4 实际应用价值

这个音乐数据分析系统具有重要的实际应用价值:

python 复制代码
# 应用场景价值
application_value = {
    "个人用户": "了解自己的音乐品味,发现新的音乐",
    "音乐爱好者": "深度分析听歌习惯,优化音乐收藏", 
    "心理学研究": "研究音乐偏好与情绪状态的关系",
    "音乐推荐": "为音乐平台提供个性化推荐算法参考",
    "文化研究": "分析音乐品味与社会文化因素的关系"
}

代码自查说明:本文所有代码均经过基本测试,但在实际使用前请注意:

  1. API限制:Spotify和网易云音乐API有调用频率限制
  2. 数据隐私:妥善处理用户敏感数据,遵守隐私政策
  3. 错误处理:完善网络请求失败和API限制的处理
  4. 依赖管理:确保所有依赖库正确安装和配置
  5. 数据备份:定期备份重要的分析结果

使用建议:为了获得最佳分析效果,建议:

  • 收集至少1-3个月的听歌数据
  • 定期更新数据以反映最新的听歌习惯
  • 结合多个数据源进行综合分析
  • 根据分析结果调整音乐发现策略

这个音乐数据分析项目不仅展示了Python在数据处理和机器学习方面的强大能力,更为用户提供了深入了解自己音乐品味的科学工具。通过数据驱动的洞察,用户可以更好地理解自己的音乐偏好,发现新的音乐体验,甚至通过音乐来更好地理解自己的情绪状态。

相关推荐
子午42 分钟前
【民族服饰识别系统】Python+TensorFlow+Vue3+Django+人工智能+深度学习+卷积网络+resnet50算法
人工智能·python·深度学习
JienDa2 小时前
JienDa聊PHP:小红书仿站实战深度架构全解析
开发语言·架构·php
QxQ么么6 小时前
移远通信(桂林)26校招-助理AI算法工程师-面试纪录
人工智能·python·算法·面试
执笔论英雄6 小时前
Slime异步原理(单例设计模式)4
开发语言·python·设计模式
e***74958 小时前
Modbus报文详解
服务器·开发语言·php
lly2024068 小时前
ASP 发送电子邮件详解
开发语言
小徐敲java8 小时前
python使用s7协议与plc进行数据通讯(HslCommunication模拟)
开发语言·python
likuolei8 小时前
XSL-FO 软件
java·开发语言·前端·数据库
6***37948 小时前
PHP在电商中的BigCommerce
开发语言·php
猫头虎8 小时前
如何解决 pip install 编译报错 fatal error: hdf5.h: No such file or directory(h5py)问题
人工智能·python·pycharm·开源·beautifulsoup·ai编程·pip