美文网首页
2020-08-04--Pandas-02--常用基本功能

2020-08-04--Pandas-02--常用基本功能

作者: program_white | 来源:发表于2020-08-04 23:16 被阅读0次

    常用的基本功能

    当我们构建好了 Series 和 DataFrame 之后,我们会经常使用哪些功能呢?来跟我看看吧。引用上一章节中的场景,我们有一些用户的的信息,并将它们存储到了 DataFrame 中。

    因为大多数情况下 DataFrame 比 Series 更为常用,所以这里以 DataFrame 举例说明,但实际上很多常用功能对于 Series 也适用。
    创建DataFrame对象数据:

    import pandas as pd
    import numpy as np
    
    index = pd.Index(data=["Tom", "Bob", "Mary", "James"], name="name")
    data = {
        "age": [18, 30, 25, 40],
        "city": ["BeiJing", "ShangHai", "GuangZhou", "ShenZhen"],
        "sex": ["male", "male", "female", "male"]
    }
    user_info = pd.DataFrame(data=data, index=index)
    print(user_info)
    

    这是我们自己创建的数据,但是如果在一般情况下我们是不知道数据的具体情况的,所以我们需要值数据的一些具体信息。

    1.info()

    一般拿到数据,我们第一步需要做的是了解下数据的整体情况,可以使用 info 方法来查看。

    # 查看数据的整体情况
    print(user_info.info())
    # <class 'pandas.core.frame.DataFrame'>
    # Index: 4 entries, Tom to James
    # Data columns (total 3 columns):
    #  #   Column  Non-Null Count  Dtype
    # ---  ------  --------------  -----
    #  0   age     4 non-null      int64
    #  1   city    4 non-null      object
    #  2   sex     4 non-null      object
    # dtypes: int64(1), object(2)
    # memory usage: 128.0+ bytes
    # None
    

    2.head(num)和tail(num)

    如果我们的数据量非常大,我想看看数据长啥样,我当然不希望查看所有的数据了,这时候我们可以采用只看头部的 n 条或者尾部的 n 条。查看头部的 n 条数据可以使用 head 方法,查看尾部的 n 条数据可以使用 tail 方法。

    # 查看前两条数据
    p = user_info.head(2)
    print(p)
    #       age      city   sex
    # name                     
    # Tom    18   BeiJing  male
    # Bob    30  ShangHai  male
    

    3.shape和T()

    此外,Pandas 中的数据结构都有 ndarray 中的常用方法和属性,如通过 .shape 获取数据的形状,通过 .T 获取数据的转置。

    # 获取数据的形状
    print(user_info.shape)       # (4, 3)
    # 获取数据的转置
    print(user_info.T)
    # name      Tom       Bob       Mary     James
    # age        18        30         25        40
    # city  BeiJing  ShangHai  GuangZhou  ShenZhen
    # sex      male      male     female      male
    print(type(user_info.T))       # <class 'pandas.core.frame.DataFrame'>
    

    4.原有数据

    如果我们想要通过 DataFrame 来获取它包含的原有数据,可以通过 .values 来获取,获取后的数据类型其实是一个 ndarray。

    # 获取其中的原有数据,返回一个ndarray
    print(user_info.values)
    # [[18 'BeiJing' 'male']
    #  [30 'ShangHai' 'male']
    #  [25 'GuangZhou' 'female']
    #  [40 'ShenZhen' 'male']]
    print(type(user_info.values))
    # <class 'numpy.ndarray'>
    

    最后也可以通过切片获取想要的数据。--values[1:3]

    描述与统计

    1.max(),min(),mean()、quantile()、sum()

    有时候我们获取到数据之后,想要查看下数据的简单统计指标(最大值、最小值、平均值、中位数等),比如想要查看年龄的最大值,如何实现呢?

    可以直接对 age 这一列调用 max方法即可。

    # 获取年龄的最大值
    print(user_info.age.max())      # 40
    

    类似的,通过调用 min、mean、quantile、sum 方法可以实现最小值、平均值、中位数以及求和。可以看到,对一个 Series 调用 这几个方法之后,返回的都只是一个聚合结果。

    2.cumsum

    cumsum,看名字就发现它和 sum 方法有关系,事实上确实如此,cumsum 也是用来求和的,不过它是用来累加求和的,也就是说它得到的结果与原始的 Series或 DataFrame 大小相同。

    # 累加
    print(user_info.age.cumsum())
    # name
    # Tom       18
    # Bob       48
    # Mary      73
    # James    113
    # Name: age, dtype: int64
    print(type(user_info.age.cumsum()))
    # <class 'pandas.core.series.Series'>
    

    可以看到,cummax 最后的结果就是将上一次求和的结果与原始当前值求和作为当前值。这话听起来有点绕。举个例子,上面的 73 = 48 + 25。cumsum 也可以用来操作字符串类型的对象。

    print(user_info.sex.cumsum())
    # name
    # Tom                    male
    # Bob                malemale
    # Mary         malemalefemale
    # James    malemalefemalemale
    # Name: sex, dtype: object
    

    3.整体统计

    虽然说常见的各种统计值都有对应的方法,如果我想要得到多个指标的话,就需要调用多次方法,是不是显得有点麻烦呢?
    Pandas 设计者自然也考虑到了这个问题,想要一次性获取多个统计指标,只需调用 describe方法即可。

    print(user_info.describe())
    #              age
    # count   4.000000             # 统计age有多少行
    # mean   28.250000           # 统计age的均值
    # std     9.251126            # 统计age的均方差
    # min    18.000000            # 最小值
    # 25%    23.250000           # 25%的值
    # 50%    27.500000          # 50%的值
    # 75%    32.500000             # 75%的值
    # max    40.000000             # 最大值
    print(type(user_info.describe()))
    # <class 'pandas.core.frame.DataFrame'>
    

    可以看到,直接调用 describe 方法后,会显示出数字类型的列的一些统计指标,如 总数、平均数、标准差、最小值、最大值、25%/50%/75% 分位数。如果想要查看非数字类型的列的统计指标,可以设置 include=["object"] 来获得。

    print(user_info.describe(include=['object']))
    #             city   sex
    # count          4     4
    # unique         4     2
    # top     ShangHai  male
    # freq           1     3
    

    上面的结果展示了非数字类型的列的一些统计指标:总数,去重后的个数、最常见的值、最常见的值的频数。

    4.次数统计

    此外,如果我想要统计下某列中每个值出现的次数,如何快速实现呢?调用 value_counts 方法快速获取 Series 中每个值出现的次数。

    # 统计sex出现的次数
    print(user_info.sex.value_counts())
    # male      3
    # female    1
    # Name: sex, dtype: int64
    

    5.最大值/最小值的索引

    如果想要获取某列最大值或最小值对应的索引,可以使用 idxmax 或 idxmin 方法完成。

    # 如果想要获取age最大值或最小值对应的索引
    print(user_info.age.idxmax())
    # James  type:str
    print(user_info.age.idxmin())
    # Tom
    

    离散化

    有时候,我们会碰到这样的需求,想要将年龄进行离散化(分桶),直白来说就是将年龄分成几个区间,这里我们想要将年龄分成 3 个区间段。就可以使用 Pandas 的 cut 方法来完成。

    print(user_info)
    #        age       city     sex
    # name                         
    # Tom     18    BeiJing    male
    # Bob     30   ShangHai    male
    # Mary    25  GuangZhou  female
    # James   40   ShenZhen    male
    
    # 将age自动切分为三段
    cate_age = pd.cut(user_info.age,3)
    print(cate_age)
    # name
    # Tom      (17.978, 25.333]
    # Bob      (25.333, 32.667]
    # Mary     (17.978, 25.333]
    # James      (32.667, 40.0]
    # Name: age, dtype: category
    # Categories (3, interval[float64]): [(17.978, 25.333] < (25.333, 32.667] < (32.667, 40.0]]
    print(type(cate_age))          # <class 'pandas.core.series.Series'>
    

    可以看到, cut 自动生成了等距的离散区间,如果自己想定义也是没问题的。

    # 将age切分为指定区间段
    cate_age = pd.cut(user_info.age,[1,18,30,50] )
    print(cate_age)
    # name
    # Tom       (1, 18]
    # Bob      (18, 30]
    # Mary     (18, 30]
    # James    (30, 50]
    # Name: age, dtype: category
    # Categories (3, interval[int64]): [(1, 18] < (18, 30] < (30, 50]]
    

    有时候离散化之后,想要给每个区间起个名字,可以指定 labels 参数。

    # 设置label属性---区间名
    cate_age = pd.cut(user_info.age,[1,18,30,50],labels=["childhood", "youth", "middle"])
    print(cate_age)
    # name
    # Tom      childhood
    # Bob          youth
    # Mary         youth
    # James       middle
    # Name: age, dtype: category
    # Categories (3, object): ['childhood' < 'youth' < 'middle']
    

    除了可以使用 cut 进行离散化之外,qcut 也可以实现离散化。cut 是根据每个值的大小来进行离散化的,qcut 是根据每个值出现的次数来进行离散化的。

    # qcut:根据值出现的次数进行离散化的
    cate_age = pd.qcut(user_info.age,3)
    print(cate_age)
    # name
    # Tom      (17.999, 25.0]
    # Bob        (25.0, 30.0]
    # Mary     (17.999, 25.0]
    # James      (30.0, 40.0]
    # Name: age, dtype: category
    # Categories (3, interval[float64]): [(17.999, 25.0] < (25.0, 30.0] < (30.0, 40.0]]
    

    排序功能

    在进行数据分析时,少不了进行数据排序。Pandas 支持两种排序方式:按轴(索引或列)排序和按实际值排序。
    先来看下按索引排序:sort_index() 方法默认是按照索引(行标识)进行正序排的。

    print(user_info)
    #        age       city     sex
    # name
    # Tom     18    BeiJing    male
    # Bob     30   ShangHai    male
    # Mary    25  GuangZhou  female
    # James   40   ShenZhen    male
    
    # 按照索引正排
    user_sort = user_info.sort_index()
    print(user_sort)
    #        age       city     sex
    # name
    # Bob     30   ShangHai    male
    # James   40   ShenZhen    male
    # Mary    25  GuangZhou  female
    # Tom     18    BeiJing    male
    
    • 设置参数axis,ascending
    • axis为0时,对行标进行排序,为1时,对列标进行排序,默认为0
    • ascending:为True时,正序,为False时,倒序,默认为True

    如果想要按照列进行倒序排,可以设置参数 axis=1 和 ascending=False。

    # 设置参数axis,ascending
    # axis为0时,对行标进行排序,为1时,对列标进行排序,默认为0
    # ascending:为True时,正序,为False时,倒序,默认为True
    user_sort_col_F = user_info.sort_index(axis=1,ascending=False)
    print(user_sort_col_F)
    #           sex       city  age
    # name
    # Tom      male    BeiJing   18
    # Bob      male   ShangHai   30
    # Mary   female  GuangZhou   25
    # James    male   ShenZhen   40
    

    可以发现列的顺序变了。

    如果想要实现按照实际值来排序,例如想要按照年龄排序,如何实现呢?

    使用 sort_values 方法,设置参数 by="age" 即可。

    # 按照实际值来排序,例如想要按照年龄正序排序
    ageSort = user_info.sort_values(by='age')
    print(ageSort)
    #        age       city     sex
    # name
    # Tom     18    BeiJing    male
    # Mary    25  GuangZhou  female
    # Bob     30   ShangHai    male
    # James   40   ShenZhen    male
    

    当两条数据中的某个值一样时,那么就会存在优先级的问题。

    有时候我们可能需要按照多个值来排序,例如:按照年龄和城市来一起排序,可以设置参数 by 为一个 list 即可。

    注意:list 中每个元素的顺序会影响排序优先级的。

    # 按照age和城市两个标识进行排序
    ageCity_sort = user_info.sort_values(by=["age", "city"])
    print(ageCity_sort)
    #        age       city     sex
    # name                         
    # Tom     18    BeiJing    male
    # Bob     18   ShangHai    male
    # Mary    25  GuangZhou  female
    # James   40   ShenZhen    male
    

    将原数据中修改两个一样的age,进行测试。

    一般在排序后,我们可能需要获取最大的n个值或最小值的n个值,我们可以使用 nlargest 和 nsmallest 方法来完成,这比先进行排序,再使用 head(n) 方法快得多。

    # 获取的数据中某项值最大和最小的几条数据
    head = user_info.age.nlargest(2)
    print(head)
    # name
    # James    40
    # Mary     25
    # Name: age, dtype: int64
    print(type(head))            # <class 'pandas.core.series.Series'>
    
    tail = user_info.age.nsmallest(2)
    print(tail)
    # name
    # Tom    18
    # Bob    18
    # Name: age, dtype: int64
    

    函数应用

    虽说 Pandas 为我们提供了非常丰富的函数,有时候我们可能需要自己定制一些函数,并将它应用到 DataFrame 或 Series。常用到的函数有:map、apply、applymap。

    这些函数的作用就是对数据集中的数据通过该函数的参数(可以是自定义函数名,lambda表达式,也可以是字典映射)实现转换功能。

    1.map()

    map 是 Series 中特有的方法,通过它可以对 Series 中的每个元素实现转换,也就是说map值针对于数据的某一列或行进行操作替换。

    如果我想通过年龄判断用户是否属于中年人(30岁以上为中年),通过 map 可以轻松搞定它。

    print(user_info)
    #        age       city     sex
    # name
    # Tom     18    BeiJing    male
    # Bob     30   ShangHai    male
    # Mary    25  GuangZhou  female
    # James   40   ShenZhen    male
    
    # map
    c = user_info.age.map(lambda x: "yes" if x >= 30 else "no")
    print(c)
    # name
    # Tom       no
    # Bob       no
    # Mary      no
    # James    yes
    # Name: age, dtype: object
    

    当函数复杂一些时,可以在外边定义函数,将函数名传进map函数中,也可以通过字典映射的方式。

    比如,我想要通过城市来判断是南方还是北方,我可以这样操作。

    # map,字典映射的方式
    city_map = {
        "BeiJing": "north",
        "ShangHai": "south",
        "GuangZhou": "south",
        "ShenZhen": "south"
    }
    # map,闯入字典映射的方式
    c = user_info.city.map(city_map)
    print(c)
    # name
    # Tom      north
    # Bob      south
    # Mary     south
    # James    south
    # Name: city, dtype: object
    

    2.apply()

    apply 方法既支持 Series,也支持 DataFrame,在对 Series 操作时会作用到每个值上,在对 DataFrame 操作时会作用到所有行或所有列(通过 axis 参数控制)。

    • axis=0:列,axis=1,行
    # apply(),对Series来书,apply()和map()一样
    c = user_info.age.apply(lambda x: "yes" if x >= 30 else "no")
    print(c)
    # name
    # Tom       no
    # Bob       no
    # Mary      no
    # James    yes
    # Name: age, dtype: object
    
    # 对于DataFrame来说的apply()
    # 将每列的数据闯进函数中,取出每列的最大值
    c = user_info.apply(lambda x: x.max(), axis=0)
    print(c)
    # age           40
    # city    ShenZhen
    # sex         male
    # dtype: object
    

    3.applymap()

    applymap 方法针对于 DataFrame,它作用于 DataFrame 中的每个元素,它对 DataFrame 的效果类似于 apply 对 Series 的效果。

    applymap():将数据中所有除索引和列标识之外的所有数据项循环加到函数中进行操作。

    print(user_info)
    #        age       city     sex
    # name                         
    # Tom     18    BeiJing    male
    # Bob     18   ShangHai    male
    # Mary    25  GuangZhou  female
    # James   40   ShenZhen    male
    
    
    # 将数据中所有数据进行相应的替换
    def func(data):
        if type(data) == int:
            if data>=18 and data<=30:
                return '青年人'
            elif data>=30 and data<=45:
                return '中年人'
        elif type(data) == str:
            if data == 'BeiJing':
                return '北京'
            elif data == 'ShangHai':
                return '上海'
            elif data == 'GuangZhou':
                return '广州'
            elif data == 'ShenZhen':
                return '深圳'
            elif data == 'male':
                return '男'
            elif data == 'female':
                return '女'
    
    c= user_info.applymap(func)
    print(c)
    # name
    # Tom    青年人   北京   男
    # Bob    青年人   上海   男
    # Mary   青年人   广州   女
    # James  中年人   深圳   男
    

    在函数中使用字典映射,字典映射只能判断值。不能判断区间。

    def func(data):
        dic = {
            'male':'男',
            'female':'女',
            'BeiJing':'北京',
            'ShangHai':'上海',
            'ShenZhen':'深圳',
            'GuangZhou':'广州',
        }
        if isinstance(data,int):
            if data>=18 and data<=30:
                return '青年人'
            elif data>=30 and data<=45:
                return '中年人'
        elif isinstance(data,str):
            return dic[data]
    
    c= user_info.applymap(func)
    print(c)
    # name
    # Tom    青年人   北京   男
    # Bob    青年人   上海   男
    # Mary   青年人   广州   女
    # James  中年人   深圳   男
    

    修改列/索引名称

    rename()

    使用user_info.rename(columns={'oldname':'newname',...},index={'old':'new',...})

    print(user_info)
    #        age       city     sex
    # name
    # Tom     18    BeiJing    male
    # Bob     30   ShangHai    male
    # Mary    25  GuangZhou  female
    # James   40   ShenZhen    male
    
    # 修改列标识和索引(行标识)
    user_info = user_info.rename(columns={'age':'Age','city':'City','sex':'Sex'},index={'Tom':'John'})
    print(user_info)
    #        Age       City     Sex
    # name                         
    # John    18    BeiJing    male
    # Bob     18   ShangHai    male
    # Mary    25  GuangZhou  female
    # James   40   ShenZhen    male
    

    类型操作

    astype ()

    单独对某一列进行转换数据类型的话,可以通过 astype 来完成。

    print(user_info)
    #        age       city     sex
    # name
    # Tom     18    BeiJing    male
    # Bob     30   ShangHai    male
    # Mary    25  GuangZhou  female
    # James   40   ShenZhen    male
    
    # 转换数据类型
    user_type= user_info.age.astype(float)
    print(user_type)
    # name
    # Tom      18.0
    # Bob      18.0
    # Mary     25.0
    # James    40.0
    # Name: age, dtype: float64
    print(type(user_type))
    # <class 'pandas.core.series.Series'>
    

    有时候会涉及到将 object 类型转为其他类型,常见的有

    • 数字:pd.to_numeric(Series)
    • 日期:pd.to_datetime(Series)
    • 时间差:pd.to_timedelta(Series)
      例子:
      将age转为数字类型:
    # 转为数字类型
    a = pd.to_numeric(user_info.age)
    print(a)
    # name
    # Tom      18
    # Bob      18
    # Mary     25
    # James    40
    # Name: age, dtype: int64
    print(type(a))
    # # <class 'pandas.core.series.Series'>
    

    实例:
    这里给这些用户都添加一些关于身高的信息。

    user_info["height"] = ["178", "168", "178", "180cm"]
    print(user_info)
    #        age       city     sex height
    # name                                
    # Tom     18    BeiJing    male    178
    # Bob     18   ShangHai    male    168
    # Mary    25  GuangZhou  female    178
    # James   40   ShenZhen    male  180cm
    

    现在将身高这一列转为数字,很明显,180cm 并非数字,为了强制转换,我们可以传入 errors 参数,这个参数的作用是当强转失败时的处理方式。

    默认情况下,

    • errors='raise',这意味着强转失败后直接抛出异常,
    • errors='coerce'可以在强转失败时将有问题的元素赋值为 pd.NaT(对于datetime和timedelta)或 np.nan(数字)。
    • errors='ignore' 可以在强转失败时返回原有的数据。
    hei = pd.to_numeric(user_info.height)
    print(hei)
    # 直接报错
    
    hei = pd.to_numeric(user_info.height,errors='coerce')
    print(hei)
    # name
    # Tom      178.0
    # Bob      168.0
    # Mary     178.0
    # James      NaN
    # Name: height, dtype: float64
    
    hei = pd.to_numeric(user_info.height,errors='ignore')
    print(hei)
    # name
    # Tom        178
    # Bob        168
    # Mary       178
    # James    180cm
    # Name: height, dtype: object
    

    相关文章

      网友评论

          本文标题:2020-08-04--Pandas-02--常用基本功能

          本文链接:https://www.haomeiwen.com/subject/xkpwrktx.html