Python最优实现:检查列表元素是否在DataFrame列中并累加流数据
优化实现方案
你的原代码用了双重循环+iterrows()逐行迭代,在数据量较大时效率极低——iterrows()本身就有不小的性能开销,双重循环更是让时间复杂度达到O(M*N)(M是流派数量,N是DataFrame行数)。下面是几种更高效的替代方案:
方案1:利用str.contains()做向量化匹配
如果Genre列的元素是字符串格式(比如每个单元格是"Pop, Indie Folk"这类多流派拼接的字符串),可以直接用pandas的str.contains()快速筛选出包含目标流派的行,再求和:
genre_names = take(1545, all_genres) streams_on_genre = [] for genre in genre_names: # 筛选包含当前流派的行,对Streams列求和,na=False排除缺失值 total = spotify_data.loc[spotify_data['Genre'].str.contains(genre, na=False), 'Streams'].sum() streams_on_genre.append(total)
这个方案依赖pandas的向量化操作,比原代码快几十倍,不需要逐行遍历。
方案2:提前展开流派再分组求和(最优解)
如果你的Genre列每个单元格对应多个流派(不管是字符串分隔、列表还是集合),先把每个流派拆成单独的行,再一次性分组求和,后续查询直接从结果字典中取值:
# 第一步:展开Genre列,每行只保留一个流派 # 假设Genre是逗号分隔的字符串,比如"Pop, Rock",如果是列表直接跳过str.split expanded_df = spotify_data.assign(Genre=spotify_data['Genre'].str.split(', ')).explode('Genre') # 第二步:按流派分组,计算总播放量 genre_stream_map = expanded_df.groupby('Genre')['Streams'].sum().to_dict() # 第三步:从字典中提取目标流派的结果,不存在的流派返回0 genre_names = take(1545, all_genres) streams_on_genre = [genre_stream_map.get(genre, 0) for genre in genre_names]
这个方案的时间复杂度是O(N + M),只需要一次数据展开和分组,后续查询都是O(1)的字典查找,数据量越大,比原代码的提升越明显,尤其适合需要多次查询不同流派列表的场景。
方案3:针对集合类型的Genre列
如果Genre列的元素是集合(比如每个单元格是{'Pop', 'Indie'}),可以用apply快速判断流派是否在集合中:
genre_names = take(1545, all_genres) streams_on_genre = [] for genre in genre_names: total = spotify_data[spotify_data['Genre'].apply(lambda x: genre in x)]['Streams'].sum() streams_on_genre.append(total)
这个方案比原代码高效,避免了iterrows()带来的性能损耗。
内容的提问来源于stack exchange,提问作者zizo
相关产品推荐
相关产品推荐

