如何在Python Pandas DataFrame中选择每个组中的最大值?
简介
在数据分析中执行的最基本和最常见的操作之一是选择包含某些列中最大值的行。在本文中,我将向您展示如何在DataFrame中找到每个组的最大值。
更多Pandas文章,请阅读:Pandas教程
问题..
首先让我们理解这个任务,假设你有一个电影数据集,并被要求根据受欢迎程度列出每年最受欢迎的电影。
如何做到..
1.准备数据。
很好,Google上有很多数据集。我经常使用kaggle.com获取我需要进行数据分析的数据集。随意登录kaggle.com并搜索电影。下载电影数据集到目录并导入到Pandas DataFrame中。
如果您像我一样从kaggle.com下载了数据,请赞美帮助您获得数据的人。
import pandas as pd
import numpy as np
movies = pd.read_csv("https://raw.githubusercontent.com/sasankac/TestDataSet/master/movies_data.csv")
# 看看样本5行
print(f"输出 \n\n*** {movies.sample(n=5)} ")
输出
*** 预算 id 初始语言 初始标题 流行度 \
2028 22000000 235260 en 上帝之子 9.175762
2548 0 13411 en 马里布最想要的 7.314796
3279 8000000 26306 en 普雷福特 8.717235
3627 5000000 10217 en 这里的世界 7.673124
4555 0 98568 en 进入无处 3.637857
发布日期 收入 运行时间 状态 标题 \
2028 28/02/2014 67800064 138.0 已发布 上帝之子
2548 10/04/2003 0 86.0 已发布 马里布最想要的
3279 24/01/1997 589304 106.0 已发布 普雷福特
3627 14/05/1997 3263585 112.0 已发布 这里的世界
4555 22/10/2011 0 90.0 已发布 进入无处
平均数 投票数
2028 5.9 83
2548 4.7 77
3279 6.7 21
3627 6.8 103
4555 6.5 49
2. 进行一些基础数据分析以了解数据。
# 确定数据类型
print(f"输出 \n*** 数据类型为 {movies.dtypes} ")
输出
*** 数据类型为 预算 int64
id int64
initial_language object
initial_title object
popularity float64
release_date object
revenue int64
runtime float64
status object
title object
vote_average float64
vote_count int64
dtype: object
2. 现在,如果我们想要节省大量内存使用,我们可以将float64和int64的数据类型转换。但在转换数据类型之前,我们必须小心并做好功课。
# 检查最大数值
print(f"输出 \n *** 数值数据类型的最大值为-{movies.select_dtypes(exclude=['object']).unstack().max()}")
# 最大投票数值是多少
print(f" *** 投票计数的最大值为-{movies[['vote_count']].unstack().max()}")
# 电影最大运行时间是多少
print(f" *** 电影ID的最大值为-{movies[['runtime']].unstack().max()}")
输出
*** 数值数据类型的最大值为-2787965087.0
*** 投票计数的最大值为-13752
*** 电影ID的最大值为-338.0
3. 有一些列不需要以64位表示,可以降低到16位,因此让我们这样做。64位int范围从 -32768 到 +32767。 我将投票计数和运行时间进行转换,您可以对需要更少内存存储的列进行转换。
4. 现在,要查找每年最受欢迎的电影,我们需要按发布日期进行分组并获取流行度的最大值。 典型SQL如下所示。
SELECT具有最大流行度的电影从电影组按照每年发布的年份进行分组
5. 不幸的是,我们的发布日期是一个对象数据类型,有几种将它们转换为日期时间的方法。 我将选择创建一个只有年份的新列,以便可以使用该列进行分组。
movies['year'] = pd.to_datetime(movies['release_date']).dt.year.astype('Int64')
print(f"结果: \n ***{movies.sample(n=5)}")
结果
*** 预算 电影id 语言 原始标题 流行度 \
757 0 87825 en 棒球时代 18.587114
711 58000000 39514 en RED 41.430245
1945 13500000 152742 en 最美丽的挑衅 30.058263
2763 13000000 16406 en Dick 4.742537
4595 350000 764 en 恶死纪行 35.037625
上映日期 收益 影片时长 状态 标题 \
757 21/09/2012 0 111.0 上映 棒球时代
711 13/10/2010 71664962 111.0 上映 RED
1945 1/01/2013 19255873 124.0 上映 最美丽的挑衅
2763 4/08/1999 27500000 94.0 上映 Dick
4595 15/10/1981 29400000 85.0 上映 恶死纪行
电影评分 评分人数 年份
757 6.6 366 2012
711 6.6 2808 2010
1945 7.7 704 2013
2763 5.7 67 1999
4595 7.3 894 1981
方法一 – 不使用Group By
6. 我们只需要三列,电影名称,电影上映年份和流行度。因此我们选择这些列,并使用年份进行sort_values以查看结果如何。
print(f"方法1的结果: \n *** 不使用Group By")
movies[["title", "year", "popularity"]].sort_values("year", ascending=True)
结果
*** 不使用Group By
ID | 电影名称 | 年份 | 流行度 |
---|---|---|---|
4592 | 不宽容 | 1916 | 3.232447 |
4661 | 盛大游行 | 1925 | 0.785744 |
2638 | 大都市 | 1927 | 32.351527 |
4594 | 百老汇音乐喜剧 | 1929 | 0.968865 |
4457 | 潘多拉的盒子 | 1929 | 1.824184 |
… | … | … | … |
2109 | 爱在记忆消逝前 | 2016 | 53.161905 |
3081 | 森林鬼影 | 2016 | 19.865989 |
2288 | 搏击女孩 | 2016 | 1.224105 |
4255 | 史密斯的成长之路 | 2017 | 0.710870 |
4553 | 美利坚仍是家园 | 0.000000 |
共4803行 × 3列
8. 现在看结果,我们还需要按流行度排序,以获得每年最受欢迎的电影。将感兴趣的列作为列表传递。ascending=False将使排序结果按降序排列。
movies[["title", "year", "popularity"]].sort_values(["year","popularity"], ascending=False)
ID | 标题 | 年份 | 流行度 |
---|---|---|---|
4255 | 成长中的史密斯 | 2017 | 0.710870 |
788 | 死侍 | 2016 | 514.569956 |
26 | 美国队长3:内战 | 2016 | 198.372395 |
10 | 蝙蝠侠大战超人:正义黎明 | 2016 | 155.790452 |
64 | X战警:天启 | 2016 | 139.272042 |
… | … | … | … |
4593 | 百老汇的旋律 | 1929 | 0.968865 |
2638 | 大都会 | 1927 | 32.351527 |
4660 | 大游行 | 1925 | 0.785744 |
4591 | 不容忍 | 1916 | 3.232447 |
4552 | 美国仍是个好地方 | 0.000000 |
4802 行 × 3 列
9. 好了,数据现在已经完美排序。接下来的步骤是仅保留每个年份的第一个值并删除其余值。你猜怎么做呢?
我们将使用 .drop_duplicates 方法。
movies[["title", "year", "popularity"]].sort_values(["year","popularity"], ascending=False).drop_duplicates(subset="year")
ID | 标题 | 年份 | 流行度 |
---|---|---|---|
4255 | 成长中的史密斯 | 2017 | 0.710870 |
788 | 死侍 | 2016 | 514.569956 |
546 | 神偷奶爸 | 2015 | 875.581305 |
95 | 星际穿越 | 2014 | 724.247784 |
124 | 冰雪奇缘 | 2013 | 165.125366 |
… | … | … | … |
4456 | 潘多拉之匣 | 1929 | 1.824184 |
2638 | 大都会 | 1927 | 32.351527 |
4660 | 大游行 | 1925 | 0.785744 |
4591 | 不容忍 | 1916 | 3.232447 |
4552 | 美国仍是个好地方 | 0.000000 |
91 行 × 3 列
Method 2 – 使用 Group By
我们也可以用 groupby 实现相同的效果。这种方法与上面 SQL 中的方法非常相似。
print(f"输出结果\n *** Method 2 - 使用 Group By")
movies[["title", "year", "popularity"]].groupby("year", as_index=False).apply(lambda df:df.sort_values("popularity", ascending=False)
.head(1)).droplevel(0).sort_values("year", ascending=False)
输出结果
*** Method 2 - 使用 Group By
ID | 标题 | 年份 | 受欢迎程度 |
---|---|---|---|
4255 | 成长于史密斯家庭 | 2017 | 0.710870 |
788 | 死侍 | 2016 | 514.569956 |
546 | 神偷奶爸 | 2015 | 875.581305 |
95 | 星际穿越 | 2014 | 724.247784 |
124 | 冰雪奇缘 | 2013 | 165.125366 |
… | … | … | … |
3804 | 地狱天使 | 1930 | 8.484123 |
4457 | 红盒子之谜 | 1929 | 1.824184 |
2638 | 大都市 | 1927 | 32.351527 |
4661 | 大游行 | 1925 | 0.785744 |
4592 | 不宽容 | 1916 | 3.232447 |
90 行 × 3 列