zoukankan      html  css  js  c++  java
  • 数据分析 02 -Pandas

    Pandas的数据结构

    导入pandas:

    三剑客

    import pandas as pd
    from pandas import Series,DataFrame
    import numpy as np

    1、Series

     

    Series是一种类似与一维数组的对象,由下面两个部分组成:

    • values:一组数据(ndarray类型)

    • index:相关的数据索引标签

    1)Series的创建

    两种创建方式:

    (1) 由列表或numpy数组创建

    默认索引为0到N-1的整数型索引

    #使用列表创建Series
    Series(data=[1,2,3,4],index=['ds','dsa','re','gr'],name='haha')#index参数指定索引
    
    #使用numpy创建Series
    Series(data=np.arange(10,60,6))

    (2) 由字典创建:不能在使用index.但是依然存在默认索引

     

    注意:数据源必须为一维数据

    dic = {
        'math':100,
        'English':50
    }
    Series(data=dic,name='qimo')

    2)Series的索引和切片

     

    可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的是一个Series类型)。

    (1) 显式索引:

    - 使用index中的元素作为索引值 - 使用s.loc[](推荐):注意,loc中括号中放置的一定是显示索引

    注意,此时是闭区间

    s = Series(np.random.randint(60,100,size=(5,)),index=['a','b','c','d','e'])
    s
    
    s['b']

    (2) 隐式索引:

    - 使用整数作为索引值
    - 使用.iloc[](推荐):iloc中的中括号中必须放置隐式索引

    注意,此时是半开区间

    s.iloc[1]
    
    s.iloc[[1,2,3]]

    切片:隐式索引切片和显示索引切片

     
    • 显示索引切片:index和loc
    s.loc['b']
    • 隐式索引切片:整数索引值和iloc
    s.loc['a':'c']

    3)Series的基本概念

     

    可以把Series看成一个定长的有序字典

    向Series增加一行:相当于给字典增加一组键值对

    s['f'] = 100
    s

    可以通过shape,size,index,values等得到series的属性

    s.index
    s.values
    s.size
    s.shape

    可以使用s.head(),tail()分别查看前n个和后n个值

    s.head(3)
    s.tail(3)

    对Series元素进行去重

    s = Series(data=[1,1,2,2,3,3,4,4,4,5,6,7,8,7,7,66,43,342,6665,444,333,444])
    s.unique()   #Series中的去重函数

    当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况

    • 使得两个Series进行相加

    s1 = Series(data=[1,2,3,4,5],index=['a','b','c','d','e'])
    s2 = Series(data=[1,2,3,4,5],index=['a','b','c','f','g'])
    s = s1+s2
    s

    可以使用pd.isnull(),pd.notnull(),或s.isnull(),notnull()函数检测缺失数据

    s.loc[s.notnull()]   #空值检测,过滤
    
    s.iloc[[True,False,True,True,False,True,True]]   #True/False是可以作为Series的索引

    4)Series的运算

    (1) + - * /

    (2) add() sub() mul() div() : s1.add(s2,fill_value=0)

    (3) Series之间的运算

    - 在运算中自动对齐不同索引的数据
    - 如果索引不对应,则补NaN

    2、DataFrame

     

    DataFrame是一个【表格型】的数据结构。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。

    • 行索引:index

    • 列索引:columns

    • 值:values

     

    1)DataFrame的创建

    最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。

    此外,DataFrame会自动加上每一行的索引。

    使用字典创建的DataFrame后,则columns参数将不可被使用。

    同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。

    DataFrame(data=np.random.randint(60,100,size=(3,3)),index=['a','b','c'],columns=['A','B','C'])

    DataFrame属性:values、columns、index、shape

    df = DataFrame(data=np.random.randint(60,100,size=(3,3)),index=['a','b','c'],columns=['A','B','C'])
    df
    
    df.values
    df.index
    df.columns

    2)DataFrame的索引

     

    (1) 对列进行索引

    - 通过类似字典的方式 df['q'] - 通过属性的方式 df.q

    可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。

    df = DataFrame(data=np.random.randint(60,150,size=(4,2)),index=['chinese','math','english','lizong'],columns=['zhangsan','li'])
    df
    
    #修改列索引
    df['li'] = [1,2,3,4]
    df
    
    #获取前两列
    df[['zhangsan','li']]
    
    df.li
    
    df['li']

    (2) 对行进行索引

    - 使用.loc[]加index来进行行索引 - 使用.iloc[]加整数来进行行索引

    同样返回一个Series,index为原来的columns。

    df.loc['math']
    
    df.iloc[1]
    
    # 取出前2行
    df.iloc[[0,1]]

    (3) 对元素索引的方法
    - 使用列索引
    - 使用行索引(iloc[3,1] or loc['C','q']) 行索引在前,列索引在后

    df.loc['math','zhangsan']

    切片:

     

    【注意】 直接用中括号时:

    • 索引表示的是列索引

    • 切片表示的是行切片

    df['math':'lizong']

    在loc和iloc中使用切片(切列) :      df.loc['B':'C','丙':'丁']

    df.loc[:,'zhangsan':'li']

    3)DataFrame的运算

    (1) DataFrame之间的运算

    同Series一样:

    • 在运算中自动对齐不同索引的数据

    • 如果索引不对应,则补NaN

    示例:
          假设ddd是期中考试成绩,ddd2是期末考试成绩,请自由创建ddd2,并将其与ddd相加,求期中期末平均值。
    
    假设张三期中考试数学被发现作弊,要记为0分,如何实现?
    
    李四因为举报张三作弊立功,期中考试所有科目加100分,如何实现?
    
    后来老师发现有一道题出错了,为了安抚学生情绪,给每位学生每个科目都加10分,如何实现
    
    df = DataFrame(data=np.random.randint(60,150,size=(4,2)),index=['chinese','math','english','lizong'],columns=['zhangsan','li'])
    df
    
    df1 = df.copy()
    df1
    
    #假设ddd是期中考试成绩,ddd2是期末考试成绩,请自由创建ddd2,并将其与ddd相加,求期中期末平均值。
    
    df2= df1.copy()
    df2
    
    (df1+df2)/2
    
    假设张三期中考试数学被发现作弊,要记为0分,如何实现?
    df2.loc['math','zhangsan'] =0
    df2
    
    # 李四因为举报张三作弊立功,期中考试所有科目加100分,如何实现?
    df2.li += 100
    df2
    
    # 后来老师发现有一道题出错了,为了安抚学生情绪,给每位学生每个科目都加10分,如何实现?
    df2 +=10
    df2

    处理丢失数据

     

    有两种丢失数据:

    • None
    • np.nan(NaN)
     

    1. None

    None是Python自带的,其类型为python object。因此,None不能参与到任何计算中。

    2. np.nan(NaN)

    np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。

    import numpy as np
    import pandas as pd
    from pandas import DataFrame,Series
    
    type(None)
    type(np.nan)

    3. pandas中的None与NaN

     

    1) pandas中None与np.nan都视作np.nan

    np.random.seed(10)
    df = DataFrame(np.random.randint(50,200,size=(6,5)),index=['a','b','c','d','e','f'],columns=['A','B','C','D','E'])
    df
    
    #将某些数组元素赋值为nan
    df.iloc[1,3] = None
    df.iloc[2,2] = np.nan
    df.iloc[4,2] = None
    df

    2) pandas处理空值操作

    • isnull()

    • notnull()

    • dropna(): 过滤丢失数据

    • fillna(): 填充丢失数据

    (1)判断函数
    - ``isnull()`` 一般后面往往跟的是any()
    - ``notnull()``一般后面往往跟的是all()

    df.isnull().any(axis=1) # 只要有一个true 就返回true
    df.isnull().all(axis=1) #只要有一个False 就返回False,全部位true才返回true
    
    df.notnull().all(axis=1)

    df.dropna() 可以选择过滤的是行还是列(默认为行):axis中0表示行,1表示的列

    df.dropna(axis=0) # 在drop系列函数中,轴向的参数值0表示的是行,1表示的是列

    df.drop(labels='A',axis=1,inplace=True)    # drop 可以删除任意的行和列

    df1.drop(labels='abbreviation',axis=1,inplace=True)
    labels='abbreviation'#指定删除的行或列
    axis =0 代表行   =1 代表列
    inplace = True  删除后写入到原文件

    (3) 填充函数 Series/DataFrame
    - ``fillna()``:value和method参数

    np.random.seed(10)
    df = DataFrame(np.random.randint(50,200,size=(6,5)),index=['a','b','c','d','e','f'],columns=['A','B','C','D','E'])
    df
    
    #将某些数组元素赋值为nan
    df.iloc[1,3] = None
    df.iloc[2,2] = np.nan
    df.iloc[4,2] = None
    df
    
    df.fillna(value=10)

    method 控制填充的方式 bfill后向填充 ffill前向填充,可以选择前向填充还是后向填充

    df.fillna(method='ffill',axis=0)
    
    df.fillna(method='bfill',axis=0)
    
    
    #连续多个nan
    df.iloc[1,3] = None
    df.iloc[4,3] = np.nan
    df.iloc[3,2] = None
    df
    
    #解决连续nan指定填空几个 limit
    df.fillna(method='bfill',axis=0,limit=1)

    1. 创建多层列索引

     

    1) 隐式构造

    最常见的方法是给DataFrame构造函数的index或者columns参数传递两个或更多的数组

    import numpy as np
    import pandas as pd
    from pandas import DataFrame,Series
    
    #创建了一个索引对象,该索引对象为二层索引
    df = DataFrame(np.random.randint(60,100,size=(2,4)),index=['tom','jay'],columns=[['qizhong','qimo','qizhong','qimo'],['c','m','c','m']])
    df

    2) 显示构造pd.MultiIndex.from_

     
    • 使用数组
    col=pd.MultiIndex.from_product([['qizhong','qimo'],
                                    ['chinese','math']])
    
    
    #创建DF对象
    df = DataFrame(data=np.random.randint(60,120,size=(2,4)),index=['tom','jay'],
             columns=col)
    df

    2. 多层行索引

     

    除了列索引,行索引也能用上述同样的方法创建多层行索引

    3. 多层索引对象的索引与切片操作

     

    1)DataFrame的操作

     
    • 获取所有学生所有科目期末考试成绩
    df['qimo']

      获取所有学生期末的math的考试成绩

    df.qimo['math']
    • 获取tom期中所有科目的考试成绩
    df.qizhong.loc['tom']

      获取tom期末的math成绩

    df['qimo'].loc['tom','math']

    注意:在对行索引的时候,若一级行索引还有多个,对二级行索引会遇到问题!也就是说,无法直接对二级索引进行索引,必须让二级索引变成一级索引后才能对其进行索引!

    切片操作

    # 总结:
    # 访问一列或多列 直接用中括号[columnname]  [[columname1,columnname2...]]
    #访问一行或多行  .loc[indexname]
    # 访问某一个元素  .loc[indexname,columnname]  获取李四期中的php成绩
    # 行切片          .loc[index1:index2]        获取张三李四的期中成绩
    # 列切片          .loc[:,column1:column2]    获取张三李四期中的php和c++成
    
    
    
    1. 分析比较Series和DataFrame各种索引的方式,熟练掌握.loc()方法
        - 在df中索引应用在行
        - 在df中切片应用在列

     5. 聚合操作

    所谓的聚合操作:平均数,方差,最大值,最小值……

    # 计算各个科目期中期末平均成绩
    df.mean()

    pandas的拼接操作

     

    pandas的拼接分为两种:

    • 级联:pd.concat, pd.append

    • 合并:pd.merge, pd.join

     

    1. 使用pd.concat()级联

     

    pandas使用pd.concat函数,与np.concatenate函数类似,只是多了一些参数:

    objs
    axis=0
    keys
    join='outer' / 'inner':表示的是级联的方式,outer会将所有的项进行级联(忽略匹配和不匹配),而inner只会将匹配的项级联到一起,不匹配的不级联
    ignore_index=False

     

    import numpy as np
    import pandas as pd
    from pandas import DataFrame,Series
    import matplotlib.pyplot as plt
    
    df1 = DataFrame(np.random.randint(0,100,size=(4,4)),index=['a','b','c','d'],columns=['A','B','C','D'])
    df2 = DataFrame(np.random.randint(0,100,size=(3,4)),index=['a','b','c',],columns=['A','B','C','D'])
    
    pd.concat([df1,df1],axis=1,)

    2) 不匹配级联

     

    不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致

     

    有2种连接方式:

    • 外连接:补NaN(默认模式)outer
     
    • 内连接:只连接匹配的项 inner
    pd.concat([df1,df2],axis=1,join='outer')
    
    pd.concat([df1,df2],axis=1,join='inner')

    3) 使用df.append()函数添加

     

    由于在后面级联的使用非常普遍,因此有一个函数append专门用于在后面添加

    df1.append(df2)

    2. 使用pd.merge()合并

     

    merge与concat的区别在于,merge需要依据某一共同的列来进行合并

    使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。

    注意每一列元素的顺序不要求一致

     

    参数:

    • how:out取并集 inner取交集

     

    • on:当有多列相同的时候,可以使用on来指定使用那一列进行合并,on的值为一个列表

    1.加载本地excl表格数据:pd.read_excel('excel_path',sheetname=0) #sheetname 索引从0开始

    1) 一对一合并

    df1=pd.read_excel('./data.xlsx',sheet_name=1)
    df2=pd.read_excel('./data.xlsx',sheet_name=2)
    df3=pd.read_excel('./data.xlsx',sheet_name=3)
    df4=pd.read_excel('./data.xlsx',sheet_name=4)
    
    pd.merge(df1,df2,how='outer') # how 默认 是inner 内连接

    2) 一对多合并

    display(df2,df3) 
    
    pd.merge(df2,df3,how='outer')# 一对多合并

    3) 多对多合并

    display(df3,df4)
    pd.merge(df3,df4,on='手机型号',how='outer')

    4) key的规范化

     
    • 当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名 (一般用的少)
    • 当两张表没有可进行连接的列时,可使用left_on和right_on手动指定merge中左右两边的哪一列列作为连接的列
    df1 = DataFrame({'employee':['Bobs','Linda','Bill'],
                    'group':['Accounting','Product','Marketing'],
                   'hire_date':[1998,2017,2018]})
    
    df5 = DataFrame({'name':['Lisa','Bobs','Bill'],
                    'hire_dates':[1998,2016,2007]})
    
    pd.merge(df1,df5,left_on='employee',right_on='name',how='outer')

    5) 内合并与外合并:out取并集 inner取交集

     
    • 内合并:只保留两者都有的key(默认模式)
    • 外合并 how='outer':补NaN
    df6 = DataFrame({'name':['Peter','Paul','Mary'],
                   'food':['fish','beans','bread']}
                   )
    df7 = DataFrame({'name':['Mary','Joseph'],
                    'drink':['wine','beer']})
    display(df6,df7)

    pandas数据处理

     

    1、删除重复元素

     

    使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True

     

    - keep参数:指定保留哪一重复的行数据

     
    • 创建具有重复元素行的DataFrame
    import numpy as np
    import pandas as pd
    from pandas import Series,DataFrame
    
    #创建一个df
    np.random.seed(10)
    df = DataFrame(np.random.randint(0,100,size=(6,5)))
    df
    
    #手动将df的某几行设置成相同的内容
    df.iloc[1]=[4,4,4,4,4]
    df.iloc[3]=[4,4,4,4,4]
    df.iloc[4]=[4,4,4,4,4]
    df
    • 使用duplicated查看所有重复元素行
    df.duplicated(keep='last') # keep参数有first last False,不指定keep默认first保留重复的第一行
    • 删除重复元素的行
    indexs=df.loc[df.duplicated()].index
    df.drop(labels=indexs,axis=0)

      - 使用drop_duplicates()函数删除重复的行    drop_duplicates(keep='first/last'/False)

    df.drop_duplicates()

    2. 映射

     

    1) replace()函数:替换元素

     

    使用replace()函数,对values进行映射操作

    DataFrame替换操作

    - 单值替换
    - 普通替换: 替换所有符合要求的元素:to_replace=15,value='e'
    - 按列指定单值替换: to_replace={列标签:替换值} value='value'


    - 多值替换
    - 列表替换: to_replace=[] value=[]
    - 字典替换(推荐) to_replace={to_replace:value,to_replace:value}

    df.replace(to_replace=9,value='nine') # 所有的9替换成nine
    
    df.replace(to_replace=[9,4],value='nine') # 多值替换9和4,替换成nine
    
    df.replace(to_replace={4:666,9:777}) # 多值字典替换
    
    df.columns=['a','b','c','d','e']
    df
    # 按列指定单值替换: to_replace={列标签(显示索引):替换值} value='value',这里需要显示索引
    df.replace(to_replace={'d':4},value=888)
    
    注意:DataFrame中,无法使用method和limit参数

    2) map()函数:新建一列 , map函数并不是df的方法,而是series的方法

     
    • map()可以映射新一列数据

    • map()中可以使用lambd表达式

    • map()中可以使用方法,可以是自定义的方法

      eg:map({to_replace:value})

    • 注意 map()中不能使用sum之类的函数,for循环

     
    • 新增一列:给df中,添加一列,该列的值为中文名对应的英文名
    dic={
        'name':['cj','datou','tutou'],
        'salary':[14000,6000,7000],
        'dep':['sal','dev','sal']
    }
    df=DataFrame(data=dic)
    df
    df['name'].map({'cj':'常建','datou':'许硕','tutou':'吴晓东'})
    
    df['c_name']=df['name'].map({'cj':'常建','datou':'许硕','tutou':'吴晓东'})
    df

    map当做一种运算工具,至于执行何种运算,是由map函数的参数决定的(参数:lambda,函数)

    • 使用自定义函数
    #超过3000部分的钱缴纳50%的税
    df['salary'].map(aflter_salary)
    
    def aflter_salary(s):
        if s >= 3000:
            return s-(s-3000)*0.5
        return s
    
    df['aflter_salary'] = df['salary'].map(aflter_salary)
    df
    • 使用lambda表达式
    df['salary'].map(lambda s:s-(s-3000)*0.5)

    注意:并不是任何形式的函数都可以作为map的参数。只有当一个函数具有一个参数且有返回值,那么该函数才可以作为map的参数。

     

    3. 使用聚合操作对数据异常值检测和过滤

     

    使用df.std()函数可以求得DataFrame对象每一列的标准差

     
    • 创建一个1000行3列的df 范围(0-1),求其每一列的标准差
    df1 =DataFrame(np.random.random(size=(1000,3)))
    df1
    
    s_std=df1.std(axis=0)
    
    #对df应用筛选条件,去除标准差太大的数据:假设过滤条件为 C列数据大于两倍的C列标准差
    df1[1]<2*s_std[1]  # 取反 ,False作为异常值
    df1.loc[df1[1]<2*s_std[1] ]

    4. 排序

     

    使用.take()函数排序

    - take()函数接受一个索引列表,用数字表示,使得df根据列表中索引的顺序进行排序
    - eg:df.take([1,3,4,2,5])

    可以借助np.random.permutation()函数随机排序

    df.take([1,0,2],axis=0)
    • np.random.permutation(x)可以生成x个从0-(x-1)的随机数列
    n=np.random.permutation(3)
    df.take(n,axis=0)

    随机抽样

     

    当DataFrame规模足够大时,直接使用np.random.permutation(x)函数,就配合take()函数实现随机抽样

     

    5. 数据分类处理【重点】

     

    数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。

    数据分类处理:

    • 分组:先把数据分为几组
    • 用函数处理:为不同组的数据应用不同的函数以转换数据
    • 合并:把不同组得到的结果合并起来

    数据分类处理的核心: - groupby()函数 - groups属性查看分组情况 - eg: df.groupby(by='item').groups

     

    分组

    from pandas import DataFrame,Series
    df = DataFrame({'item':['Apple','Banana','Orange','Banana','Orange','Apple'],
                    'price':[4,3,3,2.5,4,2],
                   'color':['red','yellow','yellow','green','green','green'],
                   'weight':[12,20,50,30,20,44]})
    df
    • 使用groupby实现分组
    df.groupby(by='item',axis=0)
    
    df.groupby(by='item',axis=0).groups
    • 分组后的聚合操作:分组后的成员中可以被进行运算的值会进行运算,不能被运算的值不进行运算
    #给df创建一个新列,内容为各个水果的平均价格
    df.groupby(by='item',axis=0).mean()['price']
    
    df.groupby(by='item',axis=0)['price'].mean()
    
    
    计算出苹果的平均价格
    df.groupby(by='item',axis=0)['price'].mean()['Apple']
    
    汇总:将各种颜色水果的平均价格和df进行汇总
    df.groupby(by='color',axis=0)['price'].mean()
    df
    
    df['mean_price']=df['color'].map({'red':4,'green':2.75,'yellow':3.50})
    df

    6.0 高级数据聚合

     

    使用groupby分组后,也可以使用transform和apply提供自定义函数实现更多的运算

    • df.groupby('item')['price'].sum() <==> df.groupby('item')['price'].apply(sum)
    • transform和apply都会进行运算,在transform或者apply中传入函数即可
    • transform和apply也可以传入一个lambda表达式
    #求出各种水果价格的平均值
    df.groupby(by='item')['price'].mean()
    
    #使用apply函数求出水果的平均价格
    df.groupby(by='item')['price'].apply(my_mean) # apply结果是经过去重的
    
    def my_mean(s):
        sum = 0
        for i in s:
            sum += i
        return sum/s.size   #s.size 代表长度和len一样
    
    #使用transform函数求出水果的平均价格
    df.groupby(by='item')['price'].transform(my_mean)# transform结果没有去重
    幻想毫无价值,计划渺如尘埃,目标不可能达到。这一切的一切毫无意义——除非我们付诸行动。
  • 相关阅读:
    JVM调优
    Java堆空间的划分:新生代、老年代
    说一下 jvm 有哪些垃圾回收器?
    JVM的垃圾回收算法有哪些
    订单并发处理--悲观锁和乐观锁、任务队列以及订单模块开发流程
    MySQL数据库的四种事务隔离级别以及事务的并发问题(脏读/不可重复读/幻读)
    Python面试总结复习(四)
    Python面试总结复习(三)
    Django表设计,多表操作复习
    python面试总结复习(二)
  • 原文地址:https://www.cnblogs.com/TodayWind/p/13771579.html
Copyright © 2011-2022 走看看