5. 深入了解数据类型
从广义上讲,数据可以分为连续数据和分类数据。
连续数据总是数字,代表某种测量,如身高、工资或薪水。连续数据可以有无限的可能性。
而分类数据则代表离散的、有限量的数值,如汽车颜色、扑克牌的类型或麦片的品牌。
Pandas 并没有笼统地将数据分类为连续或分类数据。相反,它对许多不同的数据类型有精确的技术定义。
下面介绍常见的pandas数据类型:
float - NumPy float类型,支持缺失值。
int - NumPy整数类型,不支持缺失值。
'Int64' - pandas可空的整数类型。
object - 用于存储字符串(和混合类型)的NumPy类型。
'category' - pandas分类类型,支持缺失值。
bool - NumPy布尔类型,不支持缺失值(None变为False,np.nan 变为True)。
'boolean' - pandas nullable Boolean类型。
datetime64[ns] - NumPy日期类型,支持缺失值(NaT)。
在这个方法中,我们在 DataFrame 中显示每列的数据类型。
在你抓取数据之后,了解每一列所持有的数据类型是至关重要的,因为它从根本上改变了对它的操作种类。
如何做
1. 使用 .dtypes 属性来显示每个列名及其数据类型:
>>> movies = pd.read_csv("data/movie.csv")>>> movies.dtypescolor objectdirector_name objectnum_critic_for_reviews float64duration float64director_facebook_likes float64 ... title_year float64actor_2_facebook_likes float64imdb_score float64aspect_ratio float64movie_facebook_likes int64Length: 28, dtype: object
2. 使用 .value_counts 方法返回每个数据类型的计数:
>>> movies.dtypes.value_counts()float64 13int64 3object 12dtype: int64
3. 看看 .info 方法:
>>> movies.info()<class 'pandas.core.frame.DataFrame'>RangeIndex: 4916 entries, 0 to 4915Data columns (total 28 columns):color 4897 non-null objectdirector_name 4814 non-null objectnum_critic_for_reviews 4867 non-null float64duration 4901 non-null float64director_facebook_likes 4814 non-null float64actor_3_facebook_likes 4893 non-null float64actor_2_name 4903 non-null objectactor_1_facebook_likes 4909 non-null float64gross 4054 non-null float64genres 4916 non-null objectactor_1_name 4909 non-null objectmovie_title 4916 non-null objectnum_voted_users 4916 non-null int64cast_total_facebook_likes 4916 non-null int64actor_3_name 4893 non-null objectfacenumber_in_poster 4903 non-null float64 plot_keywords 4764 non-null objectmovie_imdb_link 4916 non-null objectnum_user_for_reviews 4895 non-null float64language 4904 non-null objectcountry 4911 non-null objectcontent_rating 4616 non-null objectbudget 4432 non-null float64title_year 4810 non-null float64actor_2_facebook_likes 4903 non-null float64imdb_score 4916 non-null float64aspect_ratio 4590 non-null float64movie_facebook_likes 4916 non-null int64dtypes: float64(13), int64(3), object(12)memory usage: 1.1+ MB
如何工作
每个 DataFrame 列都列出一个类型。
例如,列 aspect_ratio 中的每个值都是一个 64 位的浮点数,movie_facebook_likes 中的每个值都是一个 64 位的整数。
Pandas 默认其核心数值类型、整数和浮点数为 64 位,而不管所有数据在内存中的大小是否合适。
即使一列完全由整数值0组成,数据类型仍然是int64。
当调用 .dtypes 属性时,.value_counts 方法返回 DataFrame 中所有数据类型的计数。
对象数据类型 object 是一种不同于其它数据类型的数据类型。
一个对象数据类型的列可以包含任何有效的 Python 对象的值。
通常,当一列是对象数据类型时,它标志着整个列都是字符串。
当你加载CSV文件,字符串列缺失值时,pandas会为该单元格插入一个NaN(float)。所以该列可能同时有对象和浮动(缺失)值。
.dtypes 属性将把列显示为对象(或系列上的0)。它不会将其显示为混合类型列(包含字符串和浮点数)。
>>> pd.Series(["Paul", np.nan, "George"]).dtypedtype('O')
.info 方法除了打印非空值的计数外,还打印数据类型信息。
它还列出了 DataFrame 使用的内存量。这是有用的信息,但会打印在屏幕上。
如果你需要使用数据,.dtypes 属性会返回一个Pandas Series。
还有更多
几乎所有的pandas数据类型都是由NumPy构建的。
这种紧密的集成使得用户更容易将pandas和NumPy操作整合在一起。
随着pandas的规模越来越大,越来越受欢迎,事实证明对象数据类型对于所有具有字符串值的列来说过于通用,pandas创建了自己的分类数据类型来处理具有固定数量可能值的字符串(或数字)列。
6. 选择列
从 DataFrame 中选取一列返回一个Series(与DataFrame具有相同的索引),它是单维数据,只由索引和数据组成。
它是一个单一维度的数据,只由一个索引和数据组成。你也可以在没有 DataFrame 的情况下自己创建一个Series,但更常见的是将它们从 DataFrame 中提取出来。
这个方法研究了两种不同的语法来选择一列数据,即一个 Series。一种语法使用索引操作符,另一种使用属性访问(或点符号)。
如何做
1. 将列名作为字符串传递给索引操作符,以选择一个系列的数据:
>>> movies = pd.read_csv("data/movie.csv")>>> movies["director_name"]0 James Cameron1 Gore Verbinski2 Sam Mendes3 Christopher Nolan4 Doug Walker ... 4911 Scott Smith4912 NaN4913 Benjamin Roberds4914 Daniel Hsia4915 Jon GunnName: director_name, Length: 4916, dtype: object
2. 另外,你也可以使用属性访问来完成同样的任务:
>>> movies.director_name0 James Cameron1 Gore Verbinski2 Sam Mendes3 Christopher Nolan4 Doug Walker ... 4911 Scott Smith4912 NaN4913 Benjamin Roberds4914 Daniel Hsia4915 Jon GunnName: director_name, Length: 4916, dtype: object
3. 我们也可以通过 .loc (列名来提取)和 .iloc (位置来提取)这两个属性的索引来拉出一个 Series。
前者允许我们通过列名来提取,而后者则通过位置来提取。
这些在 pandas 文档中被称为基于标签和基于位置的索引。
.loc 的用法是指定行和列的选择器,并用逗号隔开。
行选择器是一个没有开头或结尾名称( : )的分片,意思是选择所有的行。
列选择器只会调出名为 director_name 的列。
.iloc 索引操作也指定了行选择器和列选择器。
行选择器是没有起始或结束索引( : )的分片,选择所有的行。
列选择器,1,拉掉第二列(记住,Python是基于零的)。
>>> movies.loc[:, "director_name"]0 James Cameron1 Gore Verbinski2 Sam Mendes3 Christopher Nolan4 Doug Walker ... 4911 Scott Smith4912 NaN4913 Benjamin Roberds4914 Daniel Hsia4915 Jon GunnName: director_name, Length: 4916, dtype: object>>> movies.iloc[:, 1]0 James Cameron1 Gore Verbinski2 Sam Mendes3 Christopher Nolan4 Doug Walker ... 4911 Scott Smith4912 NaN4913 Benjamin Roberds4914 Daniel Hsia4915 Jon GunnName: director_name, Length: 4916, dtype: object
4. Jupyter 以单色字体显示系列,并显示系列的索引、类型、长度和名称。它还会根据 pandas 的配置设置来截断数据。
关于这些的描述请看图片:
你也可以通过相应的属性查看系列的索引、类型、长度和名称:
>>> movies["director_name"].indexRangeIndex(start=0, stop=4916, step=1)>>> movies["director_name"].dtypedtype('O')>>> movies["director_name"].size4196>>> movies["director_name"].name'director_name'
5. 确认输出是一个系列:
>>> type(movies["director_name"])<class 'pandas.core.series.Series'>
6. 请注意,虽然类型被报成了对象 object ,但因为有缺失的值,Series中既有floats,也有字符串。
我们可以使用类型函数的 .apply 方法 type 来得到一个具有每个成员类型的 Series。
我们不看整个 Series 的结果,而是将 .unique 方法连锁到结果上,只看在 Director_name 列中找到的唯一类型:
>>> movies["director_name"].apply(type).unique()array([<class 'str'>, <class 'float'>], dtype=object)
如何工作
Pandas DataFrame 通常有多列(虽然也可能只有一列)。
这些列中的每一列都可以被抽出并作为一个系列来处理。
有很多技巧可以从DataFrame中取出一列。
通常情况下,最简单的方法是尝试将其作为一个属性进行访问。
属性访问是通过点运算符(.notation)完成的。这样做有很多好处:
最少的输入量
Jupyter将提供完成的名称
Jupyter将提供系列属性的完成
不过其中难免也会有一些缺点:
只适用于名称为有效 Python 属性且与现有 DataFrame 属性不冲突的列
不能创建新的列,只能更新现有的列
什么是有效的 Python 属性?
一个以字符开头并包含下划线的字母数字序列,通常这些都是小写的,以遵循标准的 Python 命名约定。
这意味着带有空格或特殊字符的列名不能与属性一起使用。
使用索引操作符( [ )选择列名时,可以使用任何列名。
你也可以用这个操作符创建和更新列。当你使用索引操作符时,Jupyter 会在列名上提供完成,但遗憾的是,不会在后续的 Series 属性上完成。
我经常发现自己使用属性访问,因为在 Series 属性上获得完成是非常方便的。
但是,我也会确保列名是有效的 Python 属性名,不与现有的 DataFrame属性冲突。
我也尽量不使用属性或索引赋值来更新,而是使用 .assign 方法。关注我们,你将在我们后面的文章中看到许多使用 .assign 的例子。
还有更多
要在Jupyter中获得完成,可以在点后按Tab键,或者在索引访问中开始一个字符串后按 Tab 键。
Jupyter会弹出一个完成列表,你可以用上下方向键突出一个,然后按 Enter 键来完成它。
这是我们对你Pandas基础知识的深度检查。但记住一点,最终还需要你去练习和做相关项目。
大脑不愿意耗费多余?能量来记忆,但是它却能在复杂任务中刻入你大脑皮层。这是进化决定的。
关注我们,帮你补上Pandas这门课。