利用Pandas操作DataFrame的列与行
介 绍
本章介绍DataFrame的许多基本操作。许多秘笈与第1章“Pandas基础”中的秘笈相似,只不过第1章主要讨论的是Series的操作。
选择多个DataFrame列
可以通过将列名称传递给DataFrame的索引操作符来选择单个列。本书1.6节“选择列”对此已有介绍。一般来说,分析人员需要关注和处理的是当前工作数据集的一个子集,而这正是通过选择多个列来获得的。在此秘笈中,我们将从movie数据集中选择所有的actor(演员)和director(导演)相关数据列。
实战操作
(1)读取movie数据集,并将所需列的列表传递给索引操作符。
>>> import pandas as pd
>>> import numpy as np
>>> movies = pd.read_csv("data/movie.csv")
>>> movie_actor_director = movies[
... [
... "actor_1_name",
... "actor_2_name",
... "actor_3_name",
... "director_name",
... ]
... ]
>>> movie_actor_director.head()
actor_1_name actor_2_name actor_3_name director_name
0 CCH Pounder Joel Dav... Wes Studi James Ca...
1 Johnny Depp Orlando ... Jack Dav... Gore Ver...
2 Christop... Rory Kin... Stephani... Sam Mendes
3 Tom Hardy Christia... Joseph G... Christop...
4 Doug Walker Rob Walker NaN Doug Walker
(2)在某些情况下,我们仅需要选择DataFrame的一列,此时使用索引操作可以返回一个Series或一个DataFrame。如果我们传递一个包含单个项目的列表,则将返回一个DataFrame;如果只传递一个包含列名称的字符串,则将返回一个Series。
>>> type(movies[["director_name"]])
<class 'pandas.core.frame.DataFrame'>
>>> type(movies["director_name"])
<class 'pandas.core.series.Series'>
(3)我们也可以使用.loc属性按名称提取出一列。因为此索引操作要求首先传递一个行选择器,所以我们将使用冒号(:)表示一个选择所有行的切片。这也可以返回一个DataFrame或Series。
>>> type(movies.loc[:, ["director_name"]])
<class 'pandas.core.frame.DataFrame'>
>>> type(movies.loc[:, "director_name"])
<class 'pandas.core.series.Series'>
原理解释
DataFrame的索引操作符非常灵活,可以接收许多不同的对象。如果传递的是一个字符串,那么它将返回一维的Series;如果将列表传递给索引操作符,那么它将以指定顺序返回列表中所有列的DataFrame。
步骤(2)显示了如何选择单个列作为DataFrame和Series。一般来说,可以使用字符串选择单个列,从而得到一个Series。如果需要一个DataFrame,则可以将列名称放在一个单元素的列表中。
步骤(3)显示了如何使用.loc属性提取Series或DataFrame。
扩展知识
在索引操作符内部传递长列表可能会导致可读性问题。为了解决这个问题,你可以先将所有列名称保存到一个列表变量中。以下代码可获得与步骤(1)相同的结果。
>>> cols = [
... "actor_1_name",
... "actor_2_name",
... "actor_3_name",
... "director_name",
... ]
>>> movie_actor_director = movies[cols]
使用Pandas时,最常见的异常之一是KeyError。该问题主要是由于错误地输入了列或索引名称。每当尝试不使用列表进行多列选择时,都很容易引发相同的错误。
>>> movies[
... "actor_1_name",
... "actor_2_name",
... "actor_3_name",
... "director_name",
... ]
Traceback (most recent call last):
...
KeyError: ('actor_1_name', 'actor_2_name', 'actor_3_name', 'director_
name')
使用方法选择列
尽管列选择通常是使用索引操作符完成的,但仍有一些DataFrame方法可以按其他方式进行选择。例如,.select_dtypes和.filter就是两个很有用的可以选择列的方法。
如果要按类型选择,则需要熟悉Pandas数据类型。在1.5节“了解数据类型”中对Pandas数据类型进行了详细说明。
实战操作
(1)读取movie数据集,然后缩短要显示的列名,最后使用.get_dtype_counts方法输出包含每种特定数据类型的列数。
>>> movies = pd.read_csv("data/movie.csv")
>>> def shorten(col):
... return (
... str(col)
... .replace("facebook_likes", "fb")
... .replace("_for_reviews", "")
... )
>>> movies = movies.rename(columns=shorten)
>>> movies.get_dtype_counts()
float64 13
int64 3
object 12
dtype: int64
(2)使用.select_dtypes方法仅选择数据类型为整数的列。
>>> movies.select_dtypes(include="int").head()
num_voted_users cast_total_fb movie_fb
0 886204 4834 33000
1 471220 48350 0
2 275868 11700 85000
3 1144337 106759 164000
4 8 143 0
(3)如果要选择所有数字列,则可以将字符串number传递给include参数。
>>> movies.select_dtypes(include="number").head()
num_critics duration ... aspect_ratio movie_fb
0 723.0 178.0 ... 1.78 33000
1 302.0 169.0 ... 2.35 0
2 602.0 148.0 ... 2.35 85000
3 813.0 164.0 ... 2.35 164000
4 NaN NaN ... NaN 0
(4)如果需要整数和字符串列,则可以执行以下操作。
>>> movies.select_dtypes(include=["int", "object"]).head()
color direc/_name ... conte/ating movie_fb
0 Color James Cameron ... PG-13 33000
1 Color Gore Verbinski ... PG-13 0
2 Color Sam Mendes ... PG-13 85000
3 Color Christopher Nolan ... PG-13 164000
4 NaN Doug Walker ... NaN 0
(5)要排除仅包含浮点数字的列,可执行以下操作。
>>> movies.select_dtypes(exclude="float").head()
color director_name ... content_rating movie_fb
0 Color James Ca... ... PG-13 33000
1 Color Gore Ver... ... PG-13 0
2 Color Sam Mendes ... PG-13 85000
3 Color Christop... ... PG-13 164000
4 NaN Doug Walker ... NaN 0
(6)选择列的另一种方法是使用.filter 方法。此方法很灵活,可以根据使用的参数搜索列名(或索引标签)。在这里,我们将使用like参数搜索所有Facebook列或包含确切字符串fb的列名称。like参数将检查列名中的子字符串。
>>> movies.filter(like="fb").head()
director_fb actor_3_fb ... actor_2_fb movie_fb
0 0.0 855.0 ... 936.0 33000
1 563.0 1000.0 ... 5000.0 0
2 0.0 161.0 ... 393.0 85000
3 22000.0 23000.0 ... 23000.0 164000
4 131.0 NaN ... 12.0 0
(7).filter方法有很多相关技巧(或参数)。例如,如果使用items参数,则可以传入一个列名称的列表。
>>> cols = [
... "actor_1_name",
... "actor_2_name",
... "actor_3_name",
... "director_name",
... ]
>>> movies.filter(items=cols).head()
actor_1_name ... director_name
0 CCH Pounder ... James Cameron
1 Johnny Depp ... Gore Verbinski
2 Christoph Waltz ... Sam Mendes
3 Tom Hardy ... Christopher Nolan
4 Doug Walker ... Doug Walker
(8).filter方法还允许使用正则表达式(regular expression),通过regex参数搜索列。例如,我们可以搜索列名称中某处有数字的所有列。
>>> movies.filter(regex=r"\d").head()
actor_3_fb actor_2_name ... actor_3_name actor_2_fb
0 855.0 Joel Dav... ... Wes Studi 936.0
1 1000.0 Orlando ... ... Jack Dav... 5000.0
2 161.0 Rory Kin... ... Stephani... 393.0
3 23000.0 Christia... ... Joseph G... 23000.0
4 NaN Rob Walker ... NaN 12.0
原理解释
步骤(1)列出了所有不同数据类型的频率。或者也可以使用.dtypes属性来获取每一列的确切数据类型。.select_dtypes方法可以在其include或exclude参数中接收一个列表或单个数据类型,并返回仅具有给定数据类型的列的DataFrame(如果使用的是exclude参数,则返回一个不包含指定类型的列的DataFrame)。列表值可以是数据类型的字符串名称,也可以是实际的Python对象。
.filter方法仅通过检查列名而不是实际数据值来选择列。此外,.filter方法具有3个互斥的参数,即item、like和regex,互斥意味着一次只能使用其中一个。
like参数接收一个字符串,并尝试查找名称中某处包含该确切字符串的所有列名称。为了获得更大的灵活性,也可以使用regex参数来通过正则表达式选择列名称。示例中 的特殊正则表达式r'\d' 表示0~9的所有数字,并且匹配其中至少包含一个数字的任何字符串。
.filter方法还带有另一个参数,即items,该参数接收一个确切的列名称的列表。这几乎是对索引操作的精确复制,只是如果其中一个字符串与列名称不匹配,则不会引发KeyError。例如,movies.filter(items = ['actor_1_name', 'asdf'])运行时就不会出现错误,并且将返回单列的DataFrame。
扩展知识
.select_dtypes比较令人头疼的地方是它的灵活性,因为它可以同时接收字符串和Python对象。以下列表详细阐释了选择许多不同列数据类型的所有可能方法。在Pandas中并没有引用数据类型的标准或首选方法,因此你最好对这两种方式均有所了解。
np.number、'number':选择整数和浮点数,而不考虑大小。 np.float64、np.float_、float、'float64'、'float_'、'float':仅选择64位浮点值。 np.float16、np.float32、np.float128、'float16'、'float32'、'float128':分别选择精确的16位、32位和128位浮点数。 np.floating、'floating':选择所有浮点值,无论大小。 np.int0、np.int64、np.int_、int、'int0'、'int64'、'int _'、'int':仅选择64位整数。 np.int8、np.int16、np.int32、'int8'、'int16'、'int32':分别选择8位、16位和32位整数。 np.integer、'integer':选择所有整数,而不考虑大小。 'Int64':选择可为空的整数;没有NumPy等效项。 np.object、'object'、'O':选择所有对象数据类型。 np.datetime64、'datetime64'、'datetime':所有日期时间均为64位。 np.timedelta64、'timedelta64'、'timedelta':所有时间增量均为64位。 pd.Categorical、'category':Pandas特有分类;没有NumPy等效项。
由于所有整数和浮点数默认为64位,因此可以使用字符串'int'或'float'来选择它们。如果要选择所有整数和浮点数,而不管它们的具体大小如何,则可以使用字符串'number'。