如何在Python Pandas DataFrame中选择每组的最大值?
简介
在数据分析过程中,最基本和最常见的操作之一是从组内选择包含某些列最大值的行。在这篇文章中,我将向您展示如何在DataFrame中查找每组的最大值。
问题…
让我们首先了解任务,假设您获得了一个电影数据集,并要求根据受欢迎程度列出每年最受欢迎的电影。
怎么做…
1.准备数据。
谷歌上有很多数据集。我经常使用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")
# see sample 5 rows print(f"Output \n\n*** {movies.sample(n=5)} ")
输出
*** budget id original_language original_title popularity \ 2028 22000000 235260 en Son of God 9.175762 2548 0 13411 en Malibu's Most Wanted 7.314796 3279 8000000 26306 en Prefontaine 8.717235 3627 5000000 10217 en The Sweet Hereafter 7.673124 4555 0 98568 en Enter Nowhere 3.637857 release_date revenue runtime status title \ 2028 28/02/2014 67800064 138.0 Released Son of God 2548 10/04/2003 0 86.0 Released Malibu's Most Wanted 3279 24/01/1997 589304 106.0 Released Prefontaine 3627 14/05/1997 3263585 112.0 Released The Sweet Hereafter 4555 22/10/2011 0 90.0 Released Enter Nowhere vote_average vote_count 2028 5.9 83 2548 4.7 77 3279 6.7 21 3627 6.8 103 4555 6.5 49
2.进行一些基本的数据分析以了解数据。
# Identify the data-types print(f"Output \n*** Datatypes are {movies.dtypes} ")
输出
*** Datatypes are budget int64 id int64 original_language object original_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的数据类型。但是,在转换数据类型之前,我们必须小心并做好功课。
# Check the maximum numeric value. print(f"Output \n *** maximum value for Numeric data type - {movies.select_dtypes(exclude=['object']).unstack().max()}") # what is the max vote count value print(f" *** Vote count maximum value - {movies[['vote_count']].unstack().max()}") # what is the max movie runtime value print(f" *** Movie Id maximum value - {movies[['runtime']].unstack().max()}")
输出
*** maximum value for Numeric data type - 2787965087.0 *** Vote count maximum value - 13752 *** Movie Id maximum value - 338.0
3.有些列不需要用64位表示,可以降低到16位,所以让我们这样做。64位int范围是从-32768到+32767。我将对vote_count和runtime进行此操作,您可以对需要更少内存存储的列进行此操作。
4.现在,要识别每年的最受欢迎电影,我们需要按release_date分组并获取popularity的最大值。一个典型的SQL查询如下所示。
SELECT movie with max popularity FROM movies GROUP BY movie released year
5.不幸的是,我们的release_date是对象数据类型,有几种方法可以将其转换为datetime。我将选择创建一个只有年份的新列,以便可以使用该列进行分组。
movies['year'] = pd.to_datetime(movies['release_date']).dt.year.astype('Int64') print(f"Output \n ***{movies.sample(n=5)}")
输出
*** budget id original_language original_title popularity \ 757 0 87825 en Trouble with the Curve 18.587114 711 58000000 39514 en RED 41.430245 1945 13500000 152742 en La migliore offerta 30.058263 2763 13000000 16406 en Dick 4.742537 4595 350000 764 en The Evil Dead 35.037625 release_date revenue runtime status title \ 757 21/09/2012 0 111.0 Released Trouble with the Curve 711 13/10/2010 71664962 111.0 Released RED 1945 1/01/2013 19255873 124.0 Released The Best Offer 2763 4/08/1999 27500000 94.0 Released Dick 4595 15/10/1981 29400000 85.0 Released The Evil Dead vote_average vote_count year 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
方法1 - 不使用GroupBy
6.我们只需要3列:电影标题、电影上映年份和受欢迎程度。所以我们选择这些列,并使用sort_values按年份排序,看看结果如何。
print(f"Output \n *** Method 1- Without Using Group By") movies[["title", "year", "popularity"]].sort_values("year", ascending=True)
输出
*** Without Using Group By
片名 | 年份 | 受欢迎程度 | |
---|---|---|---|
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 | 美国仍然是最佳去处 | <NA> | 0.000000 |
4803行 × 3列
8.现在查看结果,我们需要对受欢迎程度进行排序,以获得每年的最受欢迎电影。将感兴趣的列作为列表传递。ascending=False将使排序结果按降序排列。
movies[["title", "year", "popularity"]].sort_values(["year","popularity"], ascending=False)
片名 | 年份 | 受欢迎程度 | |
---|---|---|---|
4255 | 成长中的史密斯 | 2017 | 0.710870 |
788 | 死侍 | 2016 | 514.569956 |
26 | 美国队长:内战 | 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 | 美国仍然是最佳去处 | <NA> | 0.000000 |
4802行 × 3列
9.好了,数据现在已完美排序。所以下一步就是只保留每年的第一个值并删除其余的值。猜猜怎么做?
我们将使用.drop_duplicates方法。
movies[["title", "year", "popularity"]].sort_values(["year","popularity"], ascending=False).drop_duplicates(subset="year")
片名 | 年份 | 受欢迎程度 | |
---|---|---|---|
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 | 美国仍然是最佳去处 | <NA> | 0.000000 |
91行 × 3列
方法2 - 使用GroupBy
我们也可以用groupby实现同样的效果。这种方法与上面显示的SQL非常相似。
print(f"Output \n *** Method 2 - Using 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 - Using Group By
片名 | 年份 | 受欢迎程度 | |
---|---|---|---|
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列