You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Pandas生成类SQL分组统计的完整DataFrame结果?

如何用Pandas生成包含完整维度信息的统计结果?

背景与需求

现有数据库表结构如下:

stream_history
+ ----------+-------- +
+ played_at + song_id +
+ --------- + ------- +

songs
+ ------- + --------- + -------- +
+ song_id + song_name + album_id +
+ ------- + --------- + -------- +

artists
+ --------- + ----------- +
+ artist_id + artist_name +
+ --------- + ----------- +

artists_songs (关联表)
+ --------- + ------- +
+ artist_id + song_id +
+ --------- + ------- +

albums
+ -------- + ---------- +
+ album_id + album_name +
+ -------- + ---------- +

通过以下SQL查询获取播放数据:

select distinct played_at, song_name, sh.song_id, artist_name, 
        artists.artist_id, album_name
    from stream_history as sh
    join songs on songs.song_id = sh.song_id
    join art_songs as ars on ars.song_id = songs.song_id
    join artists on artists.artist_id = ars.artist_id
    join albums on albums.album_id = songs.album_id;

返回结果示例(注意同一播放记录因歌曲多艺人会生成多条数据):

+ --------- + --------- + --------- + ----------- + ----------- + ---------- +
+ played_at + song_name + song_id   + artist_name + artist_id   + album_name +
+ --------- + --------- + --------- + ----------- + ----------- + ---------- +
+ DATE_1    + Song_A    + SONG_A_ID + ARTIST_A    + ARTIST_A_ID + ALBUM_A    +
+ DATE_1    + Song_A    + SONG_A_ID + ARTIST_B    + ARTIST_B_ID + ALBUM_A    +
+ DATE_2    + Song_B    + SONG_B_ID + ARTIST_C    + ARTIST_C_ID + ALBUM_B    +
+ DATE_3    + Song_C    + SONG_C_ID + ARTIST_D    + ARTIST_D    + ALBUM_C    +
+ --------- + --------- + --------- + ----------- + ----------- + ---------- +

核心需求:用Pandas统计每位艺术家的播放量(对应SQL DISTINCT COUNT(artist_id))和每首歌曲的播放次数(对应SQL DISTINCT COUNT(song_id)),且结果DataFrame需包含完整的维度字段(如歌曲名、艺术家名等),格式如下:

+ ----- + --------- + ------- + ----------- + --------- + ---------- + 
+ count + song_name + song_id + artist_name + artist_id + album_name + 
+ ----- + --------- + ------- + ----------- + --------- + ---------- + 

之前尝试的groupby方法仅返回统计维度和count两列,无法满足格式要求,希望避免编写多条SQL,直接用Pandas处理。

示例测试数据:

import pandas as pd

df = pd.DataFrame([
    ['2021-07-22 14:36', 'Song A', 1, 'Artist A', 1], 
    ['2021-06-23 20:28', 'Song B', 2, 'Artist B', 2],
    ['2021-06-23 20:28', 'Song B', 2, 'Artist C', 3],
    ['2021-06-23 20:35', 'Song C', 3, 'Artist A', 1]
], columns=['Played at', 'Song', 'Song_id', 'Artist', 'Artist_id'])

解决方案

1. 按艺术家统计播放量

需要先对Played at和Song_id去重(避免同一播放记录因多艺人重复统计),再按艺术家分组统计,最后关联原表获取完整维度信息:

# 步骤1:去重,确保每条播放记录只算一次
unique_plays = df.drop_duplicates(subset=['Played at', 'Song_id'])

# 步骤2:统计每个艺术家关联的播放次数
artist_counts = unique_plays.groupby('Artist_id')['Song_id'].count().reset_index(name='count')

# 步骤3:关联原表获取完整字段,同时去重(避免同一艺术家对应多条歌曲记录)
artist_result = artist_counts.merge(
    df.drop_duplicates(subset=['Artist_id']), 
    on='Artist_id', 
    how='left'
)[['count', 'Song', 'Song_id', 'Artist', 'Artist_id']]

print(artist_result)

输出结果:

count    Song  Song_id    Artist  Artist_id
0      2  Song A        1  Artist A          1
1      1  Song B        2  Artist B          2
2      1  Song B        2  Artist C          3

2. 按歌曲统计播放次数

同样先去重,再按歌曲分组统计,最后关联完整字段:

# 步骤1:去重,确保每条播放记录只算一次
unique_plays = df.drop_duplicates(subset=['Played at', 'Song_id'])

# 步骤2:统计每首歌曲的播放次数
song_counts = unique_plays.groupby('Song_id')['Played at'].count().reset_index(name='count')

# 步骤3:关联原表获取完整字段,去重避免同一歌曲多条艺人记录
song_result = song_counts.merge(
    df.drop_duplicates(subset=['Song_id']), 
    on='Song_id', 
    how='left'
)[['count', 'Song', 'Song_id', 'Artist', 'Artist_id']]

print(song_result)

输出结果:

count    Song  Song_id    Artist  Artist_id
0      1  Song A        1  Artist A          1
1      1  Song B        2  Artist B          2
2      1  Song C        3  Artist A          1

通用化封装

可以将逻辑封装成函数,适配不同统计维度:

def get_stats(df, group_col, count_col='Played at'):
    # 去重:避免同一播放记录重复统计
    unique_plays = df.drop_duplicates(subset=['Played at', 'Song_id'])
    # 统计目标维度的播放量
    counts = unique_plays.groupby(group_col)[count_col].count().reset_index(name='count')
    # 关联原表获取完整维度字段
    result = counts.merge(
        df.drop_duplicates(subset=[group_col]), 
        on=group_col, 
        how='left'
    )
    # 调整列顺序,将count放在最前面
    cols = ['count'] + [col for col in result.columns if col != 'count']
    return result[cols]

# 按艺术家统计
print(get_stats(df, 'Artist_id'))
# 按歌曲统计
print(get_stats(df, 'Song_id'))

内容的提问来源于stack exchange,提问作者Emkay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 14:55:14