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结果没有去重
    幻想毫无价值,计划渺如尘埃,目标不可能达到。这一切的一切毫无意义——除非我们付诸行动。
  • 相关阅读:
    Leetcode 538. Convert BST to Greater Tree
    Leetcode 530. Minimum Absolute Difference in BST
    Leetcode 501. Find Mode in Binary Search Tree
    Leetcode 437. Path Sum III
    Leetcode 404. Sum of Left Leaves
    Leetcode 257. Binary Tree Paths
    Leetcode 235. Lowest Common Ancestor of a Binary Search Tree
    Leetcode 226. Invert Binary Tree
    Leetcode 112. Path Sum
    Leetcode 111. Minimum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/TodayWind/p/13771579.html
Copyright © 2011-2022 走看看