介绍
Maps允许我们一次把DataFrame 或 Series中的一列数据转换为一个值。但是,通常我们希望对数据进行分组,然后对数据所在的组执行特定的操作。
正如您将了解到的,我们使用 groupby() 函数来完成这个操作。本节我们还将讨论一些例如更复杂的 DataFrames 索引方法,以及如何对数据排序等其他主题。
分组分析
到目前为止,我们一直在大量使用的一个函数是 value_counts() 函数。我们可以通过执行以下操作完成value_counts() 函数所实现的功能:
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)print(reviews.groupby('points').points.count())
每个分值的出现次数
points80 39781 69282 183683 302584 648085 953086 1260087 1693388 1720789 1222690 1541091 1135992 961393 648994 375895 153596 52397 22998 7799 33100 19Name: points, dtype: int64
groupby() 先创建一系列reviews的分组,将相同的分值的葡萄酒分配到一组。然后,针对每一个组,我们抓取points() 列并计算葡萄酒品牌出现的次数。value_counts() 是groupby() 操作的一个快捷方式。
我们可以对这些数据使用以前使用过的任何汇总函数。例如,要获得每个评分值组中最便宜的葡萄酒,我们可以执行以下操作:
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)print(reviews.groupby('points').price.min())
points80 5.081 5.082 4.083 4.084 4.085 4.086 4.087 5.088 6.089 7.090 8.091 7.092 11.093 12.094 13.095 20.096 20.097 35.098 50.099 44.0100 80.0Name: price, dtype: float64
您可以将生成的每个组看成 DataFrame 中的只包括数据与其对应值的一个切片。我们可以直接使用apply() 方法访问这个 DataFrame ,然后我们可以以任何我们认为合适的方式操作数据。例如,下面方法可以从数据集中的每个酒庄中选择评价排名第一的葡萄酒的名称:
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)print(reviews.groupby('winery').apply(lambda df: df.title.iloc[0]))
winery1+1=3 1+1=3 NV Rosé Sparkling (Cava)10 Knots 10 Knots 2010 Viognier (Paso Robles)100 Percent Wine 100 Percent Wine 2015 Moscato (California)1000 Stories 1000 Stories 2013 Bourbon Barrel Aged Zinfande...1070 Green 1070 Green 2011 Sauvignon Blanc (Rutherford)...Órale Órale 2011 Cabronita Red (Santa Ynez Valley)Öko Öko 2013 Made With Organically Grown Grapes Ma...Ökonomierat Rebholz Ökonomierat Rebholz 2007 Von Rotliegenden Spät...àMaurice àMaurice 2013 Fred Estate Syrah (Walla Walla V...Štoka Štoka 2009 Izbrani Teran (Kras)Length: 16757, dtype: object
GroupBy.apply(func, *args, **kwargs)
apply方法将func函数应用到分组上并将结果组合在一起。
传递给apply()函数的第一个参数必须是dataframe,返回dataframe、Series或标量。然后apply将负责将结果组合到一个单独的数据帧或序列中。因此,apply是一种高度灵活的分组方法。
apply()是一种非常灵活的方法,它的缺点是比使用agg和transform等方法慢一些,Pandas提供了特殊应用方向 上提供了更广泛应用的方法可以提供更快高的效率,在考虑使用apply之前应先考虑使用它们。
对于更细粒度的控制,还可以按多个列进行分组。举个例子,下面是如何根据国家和省份挑选最好的葡萄酒:
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)print(reviews.groupby(['country', 'province']).apply(lambda df: df.loc[df.points.idxmax()]))
DataFrame.idxmax(axis=0, skipna=True)
返回请求轴方向上第一次出现最大值的索引。
axis{0 or ‘index’, 1 or ‘columns’}, default 0
要使用的轴。0或“index”表示行,1或“columns”表示列。
skipnabool, default True
排除NA/null值。如果整行/列为NA,则结果为NA(缺失值)。
返回值Series
Series.idxmax(axis=0, skipna=True, *args, **kwargs)
返回最大值的行标签, 如果多个值等于最大值,则返回具有该值的第一行标签。
country ... winerycountry province ...Argentina Mendoza Province Argentina ... Bodega Catena ZapataOther Argentina ... ColoméArmenia Armenia Armenia ... Van ArdiAustralia Australia Other Australia ... Marquis PhilipsNew South Wales Australia ... De Bortoli... ... ... ...Uruguay Juanico Uruguay ... Familia DeicasMontevideo Uruguay ... BouzaProgreso Uruguay ... PisanoSan Jose Uruguay ... Castillo ViejoUruguay Uruguay ... Narbona[425 rows x 13 columns]
另一个值得一提的可用于groupby() 方法是agg()函数,它允许您在 DataFrame 上同时运行一堆不同的函数。例如,下面代码可以生成数据集的简单统计摘要:
DataFrame.agg(func=None, axis=0, *args, **kwargs)
Parameters:func:function, str, list or dict
用于聚合数据的函数。如果是函数,则必须在传递DataFrame或传递给DataFrame.apply时使用
可接受的组合包括:
函数
表示函数名的字符串
函数和/或函数名的列表,例如[np.sum,’mean’]
轴标签的字典->函数、函数名或此类列表。
pandas.Series.agg
在指定轴上使用一个或多个操作进行聚合。(len表示分组后组中元素的个数,min最小值,max最大值)
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)print(reviews.groupby(['country']).price.agg([len, min, max]))
len min maxcountryArgentina 3800.0 4.0 230.0Armenia 2.0 14.0 15.0Australia 2329.0 5.0 850.0Austria 3345.0 7.0 1100.0Bosnia and Herzegovina 2.0 12.0 13.0Brazil 52.0 10.0 60.0Bulgaria 141.0 8.0 100.0Canada 257.0 12.0 120.0Chile 4472.0 5.0 400.0China 1.0 18.0 18.0Croatia 73.0 12.0 65.0Cyprus 11.0 11.0 21.0Czech Republic 12.0 15.0 45.0Egypt 1.0 NaN NaNEngland 74.0 25.0 95.0France 22093.0 5.0 3300.0Georgia 86.0 9.0 40.0Germany 2165.0 5.0 775.0Greece 466.0 8.0 79.0Hungary 146.0 10.0 764.0India 9.0 10.0 20.0Israel 505.0 8.0 150.0Italy 19540.0 5.0 900.0Lebanon 35.0 13.0 75.0Luxembourg 6.0 16.0 30.0Macedonia 12.0 15.0 20.0Mexico 70.0 8.0 108.0Moldova 59.0 8.0 42.0Morocco 28.0 14.0 40.0New Zealand 1419.0 7.0 130.0Peru 16.0 10.0 68.0Portugal 5691.0 5.0 1000.0Romania 120.0 4.0 320.0Serbia 12.0 15.0 42.0Slovakia 1.0 16.0 16.0Slovenia 87.0 7.0 90.0South Africa 1401.0 5.0 330.0Spain 6645.0 4.0 770.0Switzerland 7.0 21.0 160.0Turkey 90.0 14.0 120.0US 54504.0 4.0 2013.0Ukraine 14.0 6.0 13.0Uruguay 109.0 10.0 130.0
有效地使用groupby()方法会允许您对数据集执行许多非常强大的操作。
多索引
到目前为止,在我们看到的所有示例中,我们都使用带有单个标签索引的DataFrame或Series对象。groupby() 稍有不同,根据我们运行的操作不同,它有时会导致所谓的多索引。
多索引不同于常规索引,因为它有多个级别。例如:
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)countries_reviewed = reviews.groupby(['country', 'province']).description.agg([len])print(countries_reviewed)
lencountry provinceArgentina Mendoza Province 3264Other 536Armenia Armenia 2Australia Australia Other 245New South Wales 85... ...Uruguay Juanico 12Montevideo 11Progreso 11San Jose 3Uruguay 24[425 rows x 1 columns]
mi = countries_reviewed.indexprint(type(mi)) # <class 'pandas.core.indexes.multi.MultiIndex'>
多索引有一些单索引没有的、能够处理分层结构的方法。它们还需要两个级别的标签来检索值。对于刚接触 pandas的用户来说,处理多索引输出是一个常见的“陷阱””gotcha”。
在pandas文档的multi index/Advanced Selection部分中,将详细介绍多索引的用例以及使用它们的说明。
但是,通常最常用的多索引方法是用于转换回常规索引的方法reset_index() 方法:
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)countries_reviewed = reviews.groupby(['country', 'province']).description.agg([len])print(countries_reviewed.reset_index())
country province len0 Argentina Mendoza Province 32641 Argentina Other 5362 Armenia Armenia 23 Australia Australia Other 2454 Australia New South Wales 85.. ... ... ...420 Uruguay Juanico 12421 Uruguay Montevideo 11422 Uruguay Progreso 11423 Uruguay San Jose 3424 Uruguay Uruguay 24[425 rows x 3 columns]
排序
回头再看一下根据countries_reviewed的结果,我们可以看到分组返回的数据是按索引顺序返回的,而不是按值顺序返回的。也就是说,当输出groupby的结果时,行的顺序取决于索引中的值,而不是数据中的值。
为了得到我们想要的顺序的数据,可以自己排序。sort_values() 方法可以方便的实现这个功能。
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)countries_reviewed = reviews.groupby(['country', 'province']).description.agg([len])countries_reviewed = countries_reviewed.reset_index()print(countries_reviewed.sort_values(by='len'))
DataFrame.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill='')Series.reset_index(level=None, drop=False, name=None, inplace=False)
重置索引或其级别。
重置DataFrame的索引,并使用默认索引。如果DataFrame具有多重索引,则此方法可以删除一个或多个级别。
country province len179 Greece Muscat of Kefallonian 1192 Greece Sterea Ellada 1194 Greece Thraki 1354 South Africa Paardeberg 140 Brazil Serra do Sudeste 1.. ... ... ...409 US Oregon 5373227 Italy Tuscany 5897118 France Bordeaux 5941415 US Washington 8639392 US California 36247[425 rows x 3 columns]
sort_values() 默认为最低值优先的升序排序。然而,大多数情况下,我们需要一个最高的数字排第一的降序排序,可以用指定参数 ascending=False 的方法实现:
DataFrame.sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False, key=None)
按任意轴的值排序,默认升序,’quicksort’算法(快速排序算法)。
by:str or list of str 字符串或字符串的列表
要排序的名称或名称列表。
如果轴为0或“index”,则by可能包含索引级别和/或列标签。
如果axis为1或“columns”,则by可能包含列级别和/或索引标签。
在版本0.23.0中更改:允许指定索引或列级别名称。
Series.sort_values(axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False, key=None)
按值排序,按某种标准按升序或降序对序列进行排序。
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)countries_reviewed = reviews.groupby(['country', 'province']).description.agg([len])countries_reviewed = countries_reviewed.reset_index()print(countries_reviewed.sort_values(by='len', ascending=False))
country province len392 US California 36247415 US Washington 8639118 France Bordeaux 5941227 Italy Tuscany 5897409 US Oregon 5373.. ... ... ...101 Croatia Krk 1247 New Zealand Gladstone 1357 South Africa Piekenierskloof 163 Chile Coelemu 1149 Greece Beotia 1[425 rows x 3 columns]
若要按索引值排序,请使用一个类似的方法sort_index(),此方法与 sort_values() 方法具有相同的参数和默认顺序:
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)countries_reviewed = reviews.groupby(['country', 'province']).description.agg([len])print(countries_reviewed.sort_index())
lencountry provinceArgentina Mendoza Province 3264Other 536Armenia Armenia 2Australia Australia Other 245New South Wales 85... ...Uruguay Juanico 12Montevideo 11Progreso 11San Jose 3Uruguay 24[425 rows x 1 columns]
最后,要知道可以同时按多个列排序:
import pandas as pdreviews = pd.read_csv("../data/winemag-data-130k-v2.csv", index_col=0)countries_reviewed = reviews.groupby(['country', 'province']).description.agg([len])print(countries_reviewed.sort_values(by=['country', 'len']))
lencountry provinceArgentina Other 536Mendoza Province 3264Armenia Armenia 2Australia Tasmania 42New South Wales 85... ...Uruguay Montevideo 11Progreso 11Juanico 12Uruguay 24Canelones 43[425 rows x 1 columns]
