Pandas 进阶(待完善)
在 NumPy 和 Pandas 入门一文里已介绍了 Pandas 的安装方式,本文会直接详细介绍 Pandas 的常用类型 Series 和 DataFrame 所包含的各种方法,推荐全文检索
载入
终端里进入 Python 的 交互式解释器(interactive interpreter),并载入 Pandas
$ python
Python 3.6.5 |Anaconda, Inc.| (default, Apr 26 2018, 08:42:37)
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas as pd
Pandas 里的 Series 类型
Series 类型的常见 Methods
## 把 list 类型转换为 Series 类型 >>> s = pd.Series(list('abbca')) ## Series 的数据结构由左边的 index 和右边的 values 组成,还有隐藏参数 position(根据从上到下的顺序,按位置排列,0 是第一位,1是第二位) ## Series 里的 index 可以是其他类型,不一定是整数 >>> s 0 a 1 b 2 b 3 c 4 a dtype: object ## 判断某个元素(element)是否在 Series 的 index 里 >>> 1 in s True >>> "a" in s False ## 将 Series 里的元素去重 - 相当于变为集合(set) >>> s.unique() array(['a', 'b', 'c'], dtype=object) ## 取出 Series 里值为 b 的所有元素(element),返回一个 Series 类型的子集 >>> s[s == "b"] 1 b 2 b ## 寻找 Series 里值为 b 的元素(element)所对应的 index 的值 >>> s[s == "b"].index Int64Index([1, 2], dtype='int64') ## 取第一个 index 的值 >>> s[s == "b"].index[0] 1 ## 根据 index 移除 Series 里的某一个元素 - 返回新的 Series 而不改变原来的变量 s 的值 >>> s.drop(index=1) 0 a 2 b 3 c 4 a dtype: object ## 接下来就可以判断某个元素(element)否在 Series 的值(value)里 >>> "a" in s.unique() True ## 根据 index 排序 - 返回一个新的 Series ,内部元素根据 index 大小排列 >>> s.sort_index() >>> s_list = pd.Series([ ... ['slim', 'waist', 'man'], ... ['slim', 'waistline'], ... ['santa']]) >>> s_list 0 [slim, waist, man] 1 [slim, waistline] 2 [santa] dtype: object ## 将一个 Series 里的所有 list 类型数据的元素合成一个新的 Series >>> one_united_series = s_list.apply(pd.Series).stack().reset_index(drop=True) >>> one_united_series 0 slim 1 waist 2 man 3 slim 4 waistline 5 santa dtype: object
Series 类型的向量运算
pandas 里的 Series 类型的相加是根据 index 匹配相加减的,而不是根据 position
## 相加的几种情况 ## Addition when indexes are the same >>> s1 = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd']) >>> s2 = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd']) >>> print(s1 + s2) a 11 b 22 c 33 d 44 dtype: int64 ## Indexes have same elements in a different order s3 = pd.Series([10, 20, 30, 40], index=['b', 'd', 'a', 'c']) >>> print(s1 + s3) a 31 b 12 c 43 d 24 dtype: int64 ## Indexes overlap, but do not have exactly the same elements >>> s4 = pd.Series([10, 20, 30, 40], index=['c', 'd', 'e', 'f']) >>> print(s1 + s4) a NaN b NaN c 13.0 d 24.0 e NaN f NaN dtype: float64 ## Indexes do not overlap >>> s5 = pd.Series([10, 20, 30, 40], index=['e', 'f', 'g', 'h']) >>> print(s1 + s5) a NaN b NaN c NaN d NaN e NaN f NaN g NaN h NaN dtype: float64
一维数据s1.loc['a']
按照 Series 类型的索引(index)读取s1.iloc[1]
按照 Series 类型的位置(position)读取,相当于 s1[1]
Pandas 里的 DataFrame 类型
pandas.DataFrame 是一种能够有效处理 .csv
文件内容的二维数据结构,允许每一列(column)各不相同的数据类型。
二维数据
读取行(row)的方式参照一维数据
读取列(column)的方式为 s1['column_name']
s1.values
返回的是 NumPy 的 Array 类型的数据(二维数组)- 注意该类型的数据要求全部元素都是同一类型 - 一般这样做是为了求所有元素的平均值,即 s1.values.mean()
DataFrame 类型的创建
## DataFrame creation - 创建 DataFrame 类型要有 column 的值 >>> import pandas as pd ## You can create a DataFrame out of a dictionary mapping column names to values >>> df_1 = pd.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5]}) >>> df_1 A B 0 0 3 1 1 4 2 2 5 ## You can also use a list of lists or a 2D NumPy array >>> acid_df = pd.DataFrame([[3.51], [3.20], [3.26], [3.01], [3.16]], columns=['pH']) >>> acid_df pH 0 3.51 1 3.20 2 3.26 3 3.01 4 3.16 ## Subway ridership for 3 stations on 4 different days >>> ridership_df = pd.DataFrame( ... data=[[ 0, 0, 2], ... [1478, 3877, 3674], ... [1613, 4088, 3991], ... [1560, 3392, 3826]], ... index=['05-01-11', '05-02-11', '05-03-11', '05-04-11'], ... columns=['R003', 'R004', 'R005'] ... ) >>> ridership_df R003 R004 R005 05-01-11 0 0 2 05-02-11 1478 3877 3674 05-03-11 1613 4088 3991 05-04-11 1560 3392 3826 ## Grads for 4 students at two exams >>> grades_df = pd.DataFrame( ... data={'exam1': [43, 81, 78, 75], ... 'exam2': [24, 63, 56, 56], ... 'gender': ["Male", "Male", "Female", "Male"]}, ... index=['Andre', 'Barry', 'Chris', 'Dan'] ... ) >>> grades_df exam1 exam2 gender Andre 43 24 Male Barry 81 63 Male Chris 78 56 Female Dan 75 56 Male
DataFrame 类型的常用方法(methods)
## 查看整体数据的信息 - 有几行;有几列;每列的数据类型;每列多少非空数据; ## 有些列的数据是 object ,实际上它们是字符串,且这是因为它们将指针存储到字符串,而不是字符串本身 >>> grades_df.info() <class 'pandas.core.frame.DataFrame'> Index: 4 entries, Andre to Dan Data columns (total 3 columns): exam1 4 non-null int64 exam2 4 non-null int64 gender 4 non-null object dtypes: int64(2), object(1) memory usage: 128.0+ bytes ## Accessing elements ## 读取第一行,即 position = 0 的数据 >>> ridership_df.iloc[0] ## 读取 index = '05-05-11' 的数据,即第 5 行 >>> ridership_df.loc['05-05-11'] ## 读取 column = 'R003' 的数据,即第 1 列 >>> ridership_df['R003'] >>> ridership_df.R003 ## 虽然这种方式也能读 R003 列的数据,但 column 是中文名就不行了,故还是推荐上面的方式 ## 读取 position = [1, 3] 的数据 >>> ridership_df.iloc[1, 3] ## slicing 切片 - 二维数据包含两个 axis,所以第一个 row_indexer 是指定沿着 index 方向的切片,第二个是指定沿着 column 方向的切片 >>> df.loc[row_indexer,column_indexer] ## 按照 index 取值 >>> df.iloc[row_indexer,column_indexer] ## 按照 position 取值 ## Example - 读取 position = [1:4] 的数据 - 即 2 到 5 行(row)的数据 ## 两个表达式效果一样,因为右侧不填就默认是 :(即取全部) >>> ridership_df.iloc[1:4] >>> ridership_df.iloc[1:4, :] >>> df_cancer.loc[:,'id':'fractal_dimension_mean'] ## 取所有行(row),取 "id" 列到 "fractal_dimension_mean" 列之间的所有列 ## 读取 column = 'R003' 和 column = 'R005' 的数据,即第 1,3 列(column)数据 >>> ridership_df[['R003', 'R005']] ## 取出 ridership_df 里 "R003" 这一列的值大于 0 的所有行(row) >>> ridership_df[ridership_df['R003'] > 0] ## 读取第一行,即 position = 0 的数据里,最大值所在的列(column)的名字 >>> ridership_df.iloc[0].idxmax() 'R005' ## 读取第一列,即 column = 'R003' 的数据里,最大值所在的行(row)的名字 >>> ridership_df['R003'].idxmax() '05-03-11' ## 读取前 3 行 - 输出数据里的一个小片段,看数据是否正常符合预期 ## 如果直接使用 .head() 不指定数字,默认是前 5 行 >>> ridership_df.head(3) R003 R004 R005 05-01-11 0 0 2 05-02-11 1478 3877 3674 05-03-11 1613 4088 3991 05-04-11 1560 3392 3826 ## 直接改变 Dataframe 表格的某一列(columns)- 缩小为原来的 1/2 >>> ridership_df["R005"] = ridership_df["R005"]/2 >>> ridership_df R003 R004 R005 05-01-11 0 0 1.0 05-02-11 1478 3877 1837.0 05-03-11 1613 4088 1995.5 05-04-11 1560 3392 1913.0 # Pandas axis >>> df_1 A B 0 0 3 1 1 4 2 2 5 # 求和 - 针对每列求和 >>> df_1.sum() A 3 B 12 dtype: int64 # 求和 - 针对每行求和 >>> df_1.sum(axis=1) 0 3 1 5 2 7 dtype: int64 # 求和 - 针对全体数据求和 >>> df_1.values.sum() 15 # 矩阵的转置 - 反转 column 和 index,两者互换,不会改动原变量 df_1,不会动到同一块内存,而是返回一个生成新的值 >>> df_1.transpose() 0 1 2 A 0 1 2 B 3 4 5
apply 和 applymap (未完待做)
.apply()
作用在每一行或者每一列上(通过参数 axis 指定),而.applymap()
作用在每个元素上# 基本形式 df.apply(func, axis="columns") # axis 的值设为 0 或 "index" 则将函数 func 作用到 每一列(column)上 # axis 的值设为 1 或 "columns" 则将函数 func 作用到 每一行(row)上 >>> df_1.apply(lambda x:x/2, axis=0) A B 0 0.0 1.5 1 0.5 2.0 2 1.0 2.5 # 作用在特定的某一列上 - Dataframe 类型的列就是 Series 类型,Series 也有 .apply() # 此处 apply 里的函数 func 接收的参数类型是 Series 里的元素,而上面的 func 接收的参数类型是 Series 类型 >>> df_1["A"].apply(lambda x:x/2) 0 0.0 1 0.5 2 1.0 Name: A, dtype: float64 # To do >>> df.applymap()
用 Pandas 读取文件,储存为 DataFrame 数据类型进行操作
# 读取 .csv 文件,返回一个 DataFrame 类型的数据,包含了该 .csv 文件的内容 >>> df = pd.read_csv("filename.csv") # Example - 可设定分隔符号(默认是逗号,此处设定为分号),也可设定 index_col 参数来指定使用数据中的某一列作为索引(index) >>> subway_df = pd.read_csv("nyc_subway_weather.csv", sep=";", index_col=['Longitude', 'Latitude']) # 生成包含数据的 .csv 文件 # index=False 是指定不保存索引(index),index=True(默认值)则索引被保存为新的一列 Unnamed:0 >>> subway_df.to_csv('nyc_subway_weather_edited.csv', index=False) # 显示前 5 行(row)的数据 >>> df.head(5) # 显示倒数 5 行(row)的数据 >>> df.tail(5) # 显示 DataFrame 数据包含的列的名字(column names) >>> df.columns # 显示用于描述该组数据特征的内容 - 数量(count),平均值(mean),标准差(std),最小值(min),最大值(max) >>> df.describe() # 显示数据的储存方面的信息 - 包含的数据类型,非空(non-null)数量,数据占用内存容量(memory usage) >>> df.info() # 显示数据的行(rows)数和列(columns)数 - 返回的是 tuple 数据类型 >>> df.shape # 统计名为 column_name 的某列(column)中,有多少种不同的值 >>> df['column_name'].value_counts() # 统计名为 column_name 的某列中,有多少「非空」行(row)- 即有多少「非空」样本 >>> df['column_name'].count() # Example - 统计 Gender 这列中 "Male" 和 "Female" 这两种取值的数量(因为此列只有这两种取值) # 在此其实就是统计男女数量 >>> df_share_bike['Gender'].value_counts() Male 244 Female 86 Name: Gender, dtype: int64 # 返回名为 column_name 的某列中,数据的集合(去除相同重复的数据) >>> df['column_name'].unique() # 将某列的数据类型转换成 datetime 类型 >>> df["time_column_name"] = pd.to_datetime(df["time_column_name"]) # 删除(remove)不需要的列 - 注意此处 axis=1 >>> df.drop(["column_name_01", "column_name_02"], axis=1, inplace=True) # 也可以这样 drop 不需要的列,效果一样 >>> df.drop(columns=["column_name_01", "column_name_02"]) # 提取出某列中,值为 some_value 的所有行,组成一个新的 DataFrame 数据 df_new >>> df_new = df[df["column_name"] == "some_value" ] # 等效于以下 .query() 方法 - 注意引号位置,.query() 采用 string to evaluate 的方式对待传入参数 >>> df_new = df.query("column_name == 'some_value'") >>> df_new = df.query("column_name == @var") # 若要配合变量 var 使用,则要在变量前添加符号 @ # 使用 .cut() 按照取值范围分组(类似切片) - 常配合 .groupby() 一起使用 >>> bin_edges = [2.72, 3.11, 3.21, 3.32, 4.01] # 规定各个的取值范围的边界:[2.72 ~ 3.11]、[3.11 ~ 3.21]、[3.21 ~ 3.32] 和 [3.32 ~ 4.01] >>> bin_names = ["extreme", "high", "moderate", "low"] # 对每个酸度水平类别(取值范围)进行命名 # 创建 levels 列 - .cut() 返回的是 Series 类型 >>> acid_df['levels'] = pd.cut(acid_df['pH'], bin_edges, labels=bin_names) >>> acid_df pH levels 0 3.51 low 1 3.20 high 2 3.26 moderate 3 3.01 extreme 4 3.16 high
整理 DataFrame 数据
通常原始数据都有各种瑕疵,比如重复项和丢失项,DataFrame 类型提供了一些处理方法(methods)
>>> df_missing = pd.DataFrame( ... data=[[np.nan, 2, np.nan, 0], ... [3, 4, np.nan, 1], ... [np.nan, np.nan, 1, 4], ... [np.nan, 3, np.nan, 4], ... [0, 3, 1, 0]], ... columns=list('ABCD'), ... index=list('abcce')) >>> df_missing A B C D a NaN 2.0 NaN 0 b 3.0 4.0 NaN 1 c NaN NaN 1.0 4 c NaN 3.0 NaN 4 e 0.0 3.0 1.0 0 # 取每一列的均值来填充该列的丢失项 - C 列全部丢失,所以没有均值,也就没填充 # 注意要加上 inplace=True 参数才能修改 df_missing,否则就只是返回新数据而已 >>> df_filled = df_missing.fillna(df_missing.mean()) >>> df_filled A B C D a 1.5 2.0 1.0 0 b 3.0 4.0 1.0 1 c 1.5 3.0 1.0 4 c 1.5 3.0 1.0 4 e 0.0 3.0 1.0 0 # 查看重复项(默认显示第一个重复 row 的值为 True)- 默认只有全部列(column)的值都相同的行(row) >>> df_filled.duplicated() a False b False c False c True e False dtype: bool # 大型数据库用以下方法直接看「总重复数」,避免输出一堆数据 >>> sum(df_filled.duplicated()) 1 # 剔除掉重复项 - 用 inplace=True 参数修改 df_filled 本身 >>> df_filled.drop_duplicates(inplace=True) >>> df_filled A B C D a 1.5 2.0 1.0 0 b 3.0 4.0 1.0 1 c 1.5 3.0 1.0 4 e 0.0 3.0 1.0 0 # 剔除掉含有至少含有一个丢失项的行(rows) - Drop the rows where at least one element is missing # 可以设置参数 axis=1 来剔除列(columns) >>> df_drop_missed = df_missing.dropna() >>> df_drop_missed A B C D e 0.0 3.0 1.0 0 # 任何列是否有空值 - 返回 False 则没有空值,返回 True 则存在空值 >>> df_drop_missed.isnull().sum().any() False >>> df_missing.isnull().sum().any() True
groupby 用法 - pandas.DataFrame.groupby
DataFrame 类型的 groupby 也是常用的分析数据的 method
>>> df1 = pd.DataFrame({"X" : ['A', 'B', 'A', 'B'], ... "Y" : [1, 4, 3, 2], ... "Z" : [1, 2, 2, 1], ... "M" : [24,29,9,19]}) # 用 groupby 按照列 'X' 的取值分组 - 'X' 列中,取值相同的行(row)将被划分为同一组 # 看中括号可知参数可以是一个 list,即按照多个列分组,此时不同列之间的「取值组合」所对应的行(row),构成了不同的组 >>> grouped_df1=df1.groupby(["X"]) # 读取分组后的 grouped_df1 中,名为 'A' 的组 - 即得到一个由所有 X 取值为 'A' 的行(row)构成的 dataFrame 数据 >>> grouped_df1.get_group('A') X Y Z M 0 A 1 1 24 2 A 3 2 9 # 分组后可直接求出所有列(columns)中,各组的平均数等 >>> grouped_df1.mean() Y Z M X A 2.0 1.5 16.5 B 3.0 1.5 24.0 # 也可以单独查看某一列(column)里,各个组的平均数 >>> grouped_df1["Y"].mean() X A 2 B 3 Name: Y, dtype: int64 # 查看一共分了几个组 >>> grouped_df1.ngroups 2 >>> len(grouped_df1) 2 # 查看每个组的大小(Size)- 包含内容多(也就是 rows 多)的组,Size 比较大 # 此例中,值为 A 的组和值为 B 的组都包含了两个「行」(rows),即他们的 Size 一样 >>> grouped_df1.size() X A 2 B 2 dtype: int64 # .size() 返回的是一个 Series 类型,所以可以用以下方法查看 Size 排名第前 N 或后 N 的 Group >>> s = grouped_df1.size() >>> s.nlargest(1) X A 2 dtype: int64 >>> s.nlargest(2) X A 2 B 2 dtype: int64
使用 pandas.get_dummies 来对数据进行 One-hot 编码
在处理数据时,有时需要将数据中的类别信息转换成数字(数字便于计算),人们会给不同类别分别设定一个独立的变量,这些变量就被称为 dummy variables 。以性别为例(性别通常为 2 类),这时就有 2 个变量(two variables),如果是「male」则代表男性的变量值为 1 ,代表女性的变量值为 0 —— 即变量取值组合 (1,0) 为男性,(0,1) 为女性。再比如区分猫狗猪三类,此时就有 3 个变量,变量取值组合 (1,0,0) 为「猫」,(0,1,0) 为「狗」,(0,0,1) 为「猪」。这种编码方式就称为 One-hot 编码 —— 之所以不用单一变量通过取值 0 , 1 和 2 来分别编码猫狗猪,是因为这样会暗含这三个类别具有相关性而不是独立的
这个 Youtube 视频也介绍了 get_dummies 的用法,推荐参考# 使用上文的 acid_df 为例介绍 pandas.get_dummies 用法 >>> acid_df pH levels 0 3.51 low 1 3.20 high 2 3.26 moderate 3 3.01 extreme 4 3.16 high # 对 column = "levels" 这一列的值进行编码(该列的值共有 4 种) >>> pd.get_dummies(acid_df["levels"]) extreme high moderate low 0 0 0 0 1 1 0 1 0 0 2 0 0 1 0 3 1 0 0 0 4 0 1 0 0 # 根据传统,编码时要加上前缀(prefix),以进一步说明编码信息 # 此外该列的值共有 4 种,但只需要对其中 3 种进行编码就能知道所有信息,所以人们通常会抛弃其中一列 # 使用 iloc 切片实现抛弃其中一列 - 取所有行(row),取第 2 列(column)和第 2 列之后的所有列(参考上文对 iloc 的描述) >>> pd.get_dummies(acid_df["levels"], prefix="level").iloc[:, 1:] level_high level_moderate level_low 0 0 0 1 1 1 0 0 2 0 1 0 3 0 0 0 4 1 0 0 # 一步实现 5 个操作 #「编码指定的所有列(columns)」,「添加前缀(默认添加的是原列名称)」,「切片抛弃」,「整合编码后数据表和原始表 acid_df」和「把原始表 acid_df 中的 "levels" 这一列删除」 # 注意,操作后 acid_df 的内容并没有改变,整个操作只是输出一个整合后的表,需要新建变量来保存 >>> pd.get_dummies(acid_df, columns=["levels"], drop_first=True) pH levels_high levels_moderate levels_low 0 3.51 0 0 1 1 3.20 1 0 0 2 3.26 0 1 0 3 3.01 0 0 0 4 3.16 1 0 0
合并两个 DataFrame
使用 DataFrame.merge 来合并两个 DataFrame 类型的数据,可以参考这里查看 Merge 更详细的规则:
## 语法:left_df.merge(right_df, how='inner', on="column_name") ## how="left" - 合并 column_name 之外的所有列,以左边(left_df)column_name 列的取值为准,在右边(right_df)寻找同样的取值合并,找不到则合并后右列的取值为 NaN ## how="right" - 合并 column_name 之外的所有列,以右边(right_df)column_name 列的取值为准,在左边(left_df)寻找同样的取值合并,找不到则合并后左列的取值为 NaN ## how="inner" - 在左右的 column_name 列取值相同的行(row),才会合并 ## how="outer" - 无论左右的 column_name 一列是否有相同取值的行(row),都会合并,相应的列(column)的值以 NaN 填充 ## 语言是苍白的,只有尝试几次才能明白,或者查看上述官方文档的链接 # 数据一 >>> sub_df = pd.DataFrame( ... [["05-01-11", 4388333, 2911002, "R003", 0, 40.689945, -73.872564], ... ["05-02-11", 4388348, 2911036, "R004", 1, 40.691320, -73.867135]], ... columns=["DATEn", "ENTRIESn", "EXITSn", "UNIT", "hour", "latitude", "longitude"]) >>> sub_df DATEn ENTRIESn EXITSn UNIT hour latitude longitude 0 05-01-11 4388333 2911002 R003 0 40.689945 -73.872564 1 05-02-11 4388348 2911036 R004 1 40.691320 -73.867135 # 数据二 >>> wea_df = pd.DataFrame( ... [["05-01-11", 0, 40.689945, -73.872564, 30.24], ... ["05-02-11", 1, 40.691320, -73.867135, 30.32]], ... columns=["DATEn", "hour", "latitude", "longitude", "pressurei"]) >>> wea_df DATEn hour latitude longitude pressurei 0 05-01-11 0 40.689945 -73.872564 30.24 1 05-02-11 1 40.691320 -73.867135 30.32 # 合并 >>> sub_df.merge(wea_df, on=["DATEn", "latitude", "longitude", "hour"], how="inner") DATEn ENTRIESn EXITSn UNIT hour latitude longitude pressurei 0 05-01-11 4388333 2911002 R003 0 40.689945 -73.872564 30.24 1 05-02-11 4388348 2911036 R004 1 40.691320 -73.867135 30.32 # 数据三 - date 这一列和 sub_df 中的 DATEn 列名字虽然不同,但描述的是同一个东西 >>> wea_df_date date hour latitude longitude pressurei 0 05-01-11 0 40.689945 -73.872564 30.24 1 05-02-11 1 40.691320 -73.867135 30.32 # 此时我们的合并语法要加上 left_on 和 right_on 这两个参数 >>> sub_df.merge(wea_df_date, ... left_on=["DATEn", "latitude", "longitude", "hour"], ... right_on=["date", "latitude", "longitude", "hour"], ... how="inner")
将一个 DataFrame 数据添加到另一个 DataFrame 里
使用 DataFrame.append 来实现添加一个 DataFrame 类型的数据:
>>> df_base = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB')) >>> df_base A B 0 1 2 1 3 4 >>> df_addition = pd.DataFrame([[5, 6], [7, 8]], columns=list('Ab')) >>> df_addition A b 0 5 6 1 7 8 # 添加 df_addition 到 df_base 尾部 - 返回新的 DataFrame 而不改变原来的 df_base >>> df_base.append(df_addition) A B b 0 1 2.0 NaN 1 3 4.0 NaN 0 5 NaN 6.0 1 7 NaN 8.0 # 重命名列的名字(column name)- 默认返回新的 DataFrame,要改动原变量要设置参数 inplace=True >>> df_addition.rename(columns={"b": "B"}) # 参数 columns 也可以接收函数 - 此处多余的 else 是为了展示 lambda 中的完整 if 语法 >>> df_addition.rename(columns=lambda x: "B" if x == "b" else x, inplace=True) # 确认两个数据集的列标签相同 >>> df_addition.columns == df_base.columns array([ True, True]) # 如果数据太多,也可以这样确认 - 当且仅当元素(elements)都为非空,非零或者 True,.all() 返回 True >>> (df_addition.columns == df_base.columns).all() True # 再次合并 - 返回新的 DataFrame 而不改变原来的 df_base >>> df_base.append(df_addition) A B 0 1 2 1 3 4 0 5 6 1 7 8 # 设置 ignore_index=True 即可“解决” index 问题(默认 ignore_index=False),如果这是你想要的效果的话 >>> df_base.append(df_addition, ignore_index=True) A B 0 1 2 1 3 4 2 5 6 3 7 8
用 Pandas 绘制数据分析图
Pandas 库里本身就提供的绘制图像的方法(Methods)可以作用于 Series 和 DataFrame 两种类型的数据上,这些方法(Methods)都是基于常用绘图库 matplotlib 封装的(wrappers around matplotlib functions),所以名字大都和 matplotlib 里的一样。用 Pandas 绘图主要是为了快速可视化,若要更加复杂的分析图,还是得载入 Matplotlib 库(进一步查看 Matplotlib 使用指南)
# 生成直方图(histogram)- figsize 参数是设定直方图的大小(即宽高)
>>> df.hist(figsize=(8, 8))
# 可对 Series 数据类型使用
>>> df["column_name"].hist(figsize=(8, 8))
# 生成直方图的另一种方法 - 使用 title 参数添加标题
>>> df["column_name"].plot(kind="hist", title="title_name")
# 如果列的数据类型是 String ,可以配合上述的 .value_counts() 方法统计数字,然后生成图表
# 下面 kind="bar" 是生成柱状图(bar charts)- 注意区别于直方图
>>> df["string_column"].value_counts().plot(kind="bar")
# 生成饼图(pie chart)
>>> df["string_column"].value_counts().plot(kind="pie", figsize=(8, 8))
# 同时显示所有变量间的相关关系图(散点图 scatter)和直方图 - 类似锤子科技 TNT 的 Poker Dealer
>>> pd.plotting.scatter_matrix(df, figsize=(15, 15))
# 显示具体的两个变量的数据图 - 配合上述的 Poker Dealer 全变量显示后
>>> df.plot(x="column_1_name", y="column_2_name", kind="scatter")
PS:
如果你用 Jupyter notebook,记得加上 % matplotlib inline
以让图标显示在内容流中。
如果是在终端里使用 IPython,则要用 plt.show()
来显示图像:
import matplotlib.pyplot as plt
plt.plot([1,2,3,4])
plt.show()
Axis 参数
Numpy 里的 Array 类型,Pandas 里的 Series 类型和 DataFrame 类型都通常能设置一个 axis 参数,代表操作方向(是对 column 操作,还是对 row 操作),但每次用的时候都需要先测试一下,才能确保参数值 1
和 0
到底分别代表哪个方向
对于 Array 类型和 Series 类型:
axis = 0
axis = 1
对于 DataFrame 类型:
axis = 0
或axis = "index"
along the index(沿着 index 方向 - 垂直纵向)axis = 1
或axis = "columns"
along the column(沿着 column 的方向 - 水平横向)