Pandas 进阶(待完善)

    Machine Learning

NumPy 和 Pandas 入门一文里已介绍了 Pandas 的安装方式,本文会直接详细介绍 Pandas 的常用类型 SeriesDataFrame 所包含的各种方法,推荐全文检索


载入

终端里进入 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)可以作用于 SeriesDataFrame 两种类型的数据上,这些方法(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 操作),但每次用的时候都需要先测试一下,才能确保参数值 10 到底分别代表哪个方向

对于 Array 类型和 Series 类型:

  • axis = 0

  • axis = 1

对于 DataFrame 类型:

  • axis = 0axis = "index"
    along the index(沿着 index 方向 - 垂直纵向)

  • axis = 1axis = "columns"
    along the column(沿着 column 的方向 - 水平横向)


打赏