zoukankan      html  css  js  c++  java
  • 数据分析之重要模块pandas

    1.简介

    基于Numpy构建
    pandas的出现,让Python语言成为使用最广泛而且强大的数据分析环境之一
    
    pandas的主要功能
        - 具备诸多功能的两大数据结构
          Series、DataFrame(核心)
        都是基于Numpy构建出来的
            公司中使用频繁的是DataFrame,而Series是构成DataFrame的基础,即一个DataFrame可能由N个Series构成
        - 集成时间序列功能
        - 提供丰富的数学运算和操作(基于Numpy)
        - 灵活处理缺失数据

    安装方法:
      # python环境下
      pip install pandas
      # anaconda环境下
      conda install pandas
      '''anaconda已经自动帮助我们下载好了数据分析相关的模块,其实无需我们再下载'''

    导入方法
      import pandas as pd

    掌握目标

    1. 掌握外部数据的读取
    2. 如何快速地认知数据的概览信息
    3. 数据子集的筛选与清洗
    4. 数据的汇总处理
    5. 数据的合并与连接

    常用pandas解析函数

    pandas提供了一些用于将表格型数据读取为DataFrame对象的函数

    函数描述 
    read_csv 从文件、url或者文件型对象读取分割好的数据,逗号是默认分隔符  
    read_table 从文件、url或者文件型对象读取分割好的数据,制表符(' ')是默认分隔符  
    read_fwf 读取定宽格式数据(无分隔符)  
    read_clipboard 读取剪贴板中的数据,可以看做read_table的剪贴板。再将网页转换为表格  
    read_excel 从Excel的XLS或者XLSX文件中读取表格数据  
    read_hdf 读取pandas写的HDF5文件  
    read_html 从HTML文件中读取所有表格数据  
    read_json 从json字符串中读取数据  
    read_pickle 从Python pickle格式中存储的任意对象  
    read_msgpack 二进制格式编码的pandas数据  
    read_sas 读取存储于sas系统自定义存储格式的SAS数据集  
    read_stata 读取Stata文件格式的数据集  
    read_feather 读取Feather二进制文件格式  
    read_sql 将SQL查询的结果(SQLAlchemy)读取为pandas的DataFrame

    2.数据结构之Series

    # 是一种类似于一维数组对象,由数据和相关的标签(索引)组成
    # 左侧是行标签,右侧是真实数据
    第一种:
    pd.Series([4,5,6,7,8])  
    
    第二种:
    pd.Series([4,5,6,7,8],index=['a','b','c','d','e'])
    a    4
    b    5
    c    6
    d    7
    e    8
    dtype: int64
    
    第三种:
    pd.Series({"a":1,"b":2})
    
    第四种:
    pd.Series(0,index=['a','b','c'])

    2.1 Series缺失数据概念

    st = {"tony":18,"yang":19,"bella":20,"cloud":21}
    obj = pd.Series(st)
    obj
    new_st = {'tony','yang','cloud','jason'}
    # new_st
    obj1 = pd.Series(st,index=new_st)
    obj1  # 这么写就会出现缺失数据
    # tony     18.0
    # jason     NaN
    # cloud    21.0
    # yang     19.0
    # dtype: float64
    """NaN表示缺失数据,本身属于浮点型"""
    # 下面的方法就没有缺失数据
    obj.index = new_st
    obj
    
    小疑问:为什么运算完之后数据类型会由原来的int64变成float64?
        因为NaN其实是float类型
        type(np.nan) 
        结果是:float

    2.2 处理缺失数据

    dropna()  # 过滤掉值为NaN的行
    fillna()  # 填充缺失数据
    isnull()  # 返回布尔数组,判断缺失值
    notnull()  # 返回布尔数组,取反:不是缺失值
    
    补充:
      对数据进行处理返回一个新的结果原数据不变,如果想要直接影响原数据需要加参数inplace=True
    
    举例:根据2.1
    obj1.isnull()
    # tony     False
    # jason     True
    # cloud    False
    # yang     False
    # dtype: bool
    obj1.notnull()
    # tony      True
    # jason    False
    # cloud     True
    # yang      True
    # dtype: bool
    obj1.fillna(value=666)
    # tony      18.0
    # jason    666.0
    # cloud     21.0
    # yang      19.0
    # dtype: float64
    """
      在notebook环境下,如果一个编辑命令有结果,说明该编辑命令没有修改原数据 如果一个修改命令没有结果,说明修改的是原数据
    如果你想直接修改源数据,可以加一个苦丁的参数inplace=True
    obj1.fillna(666,inplace=True)
    obj1
    # tony 18.0
    # jason 666.0
    # cloud 21.0
    # yang 19.0
    # dtype: float6
    """
    obj1.dropna()
    # tony     18.0
    # cloud    21.0
    # yang     19.0
    # dtype: float64

    2.3  布尔选择器

    mask = pd.Series([True,False,False,True,False])
    price = pd.Series([321312,123,324,5654,645])
    # price[mask] # 拿出True
    # price|mask   #或
    # price&mask   #逻辑运算
    '''涉及到逻辑运算符,符号左右两边的条件必须加上括号'''
    (price>200) & (price<900)  # 逻辑运算
    price[(price>200) & (price<900)]  # 布尔求值

    2.4 索引

    s1 = pd.Series([321312,123,324,5654,645])
    s1[0] # 321212   0不是索引值,是行标签或者叫行索引
    # s2= pd.Series([321312,123,324,5654,645],index=[1,2,3,4,5])
    # s2[0]  # 报错,行标签没有索引0
    s2= pd.Series([321312,123,324,5654,645],index=['a','b','c','d','e'])
    s2['b'] # 行标签
    s2[0]  # 行索引:当左侧行索引不是数字时,可以支持从0开始的索引值
    
    sr = pd.Series(np.arange(10))
    sr1 = sr[3:]
    sr1
    # sr1[1]  # 报错
    
    """
    为了能够自己主动区分到底是用左侧的标签名还是索引值
    """
    sr1
    #使用索引取值
    sr1.iloc[0]  #3 以索引下标解释
    # 使用行标签
    sr1.loc[3]  #3,不看左侧标签了,直接按数字0标签开始取值

    2.5 数据操作-增删改查

    res = pd.Series([11,22,33,44,55,66])
    # 增加一行数据
    res['cxiong']=18
    # 修改
    res.iloc[0] = 1111
    # 查询
    # res.loc[1]
    # res.iloc[1:3]
    # 数据纵向合并
    # res1=pd.Series(['a','b','c','d'])
    # res.append(res1)
    # 删除
    del res[0]

    2.6 基本算术方法

    """
    add 加
    sub 减
    div 除
    mul 乘
    """
    sr1 = pd.Series([12,23,34], index=['c','a','d'])
    sr3 = pd.Series([11,20,10,14], index=['d','c','a','b'])
    sr1.add(sr3,fill_value=0)  # 没有对象进行填充
    # a    33.0
    # b    14.0
    # c    32.0
    # d    45.0
    # dtype: float64

    3. 数据结构之DataFrame

    # 表格型数据结构,相当于一个二维数组,含有一组有序的列也可以看作是由Series组成的共用一个索引的字典
    
    # DataFrame就是表格型数据
    # 创建DataFrame的方式
    第一种:
    res = pd.DataFrame({'one':[1,2,3,4],'two':[4,3,2,1]})
    第二种:
    pd.DataFrame({'one':pd.Series([1,2,3],index=['a','b','c']),'two':pd.Series([1,2,3],index=['b','a','c'])})
    第三种:
    pd.DataFrame(np.array([10,20],[30,40]),index=['a','b'],columns=['c1','c2'])
    更多
    pd.DataFrame([np.arange(1,8),np.arange(11,18)])
    s1 = pd.Series(np.arange(1,9,2))
    s2 = pd.Series(np.arange(2,10,2))
    s3 = pd.Series(np.arange(5,7),index=[1,2])
    df5 = pd.DataFrame({'c1':s1,'c2':s2,'c3':s3})
    
    """
    以上创建方式都仅仅做一个了解即可 因为工作中dataframe的数据一般都是来自于读取外部文件数据,而不是自己手动去创建
    外部文件:1.普通文本文件 2.excel文件(10W行以上用这个) 3.关系型数据库表数据
    """

    4.DataFrame常用属性

    """
    1.index    行索引
    2.columns  列索引
    3.T                 转置
    4.values   值索引
    5.describe 快速统计
    """
    res = pd.DataFrame({'one':[1,2,3,4],'two':[4,3,2,1]})
    # 查看表行索引
    res.index
    # 查询列字段
    res.columns # 字符串类型在DataFrame中用object表示
    # 修改行索引
    res.index=[11,22,33,44]
    # 修改列字段
    res.columns=['id','uid']
    # 转置:列名称变为行索引,行索引变为列名称
    res.T
    # 获取表单数据(不要行索引和列名称)
    res.values
    # 结果
    # array([[1, 4],
    #        [2, 3],
    #        [3, 2],
    #        [4, 1]], dtype=int64)
    
    # 快速统计:
    res.describe()  #默认只统计数值类型
    # 当res不是数字类型
    res= pd.DataFrame({'username':['xc','cx','xc','kk'],'pwd':[123,321,222,333]})
    res.describe(include='all')
    # res.describe(include='object/all/int')

    5. 外部文件读取

    5.1数据读取之read_csv

    # # 读取text文件和csv  结尾的文件
    pd.read_csv(filepath_or_buffer, sep=‘,', header='infer', names=None, usecols=None, skiprows=None, skipfooter=None, converters=None, encoding=None)
    
    read_csv参数:            
    filepath_or_buffer:指定txt文件或csv文件所在的具体路径 
    sep:指定原数据集中各字段之间的分隔符,默认为逗号”,” 
              id    name    income
            1   cxiong     10
    header:是否需要将原数据集中的第一行作为表头,默认将第一行用作字段名称 
            如果原始数据没有表头需要将该参数设置为None 
    names:如果原数据集中没有字段,可以通过该参数在数据读取时给数据框添加具体的表头 
    usecols:指定需要读取原数据集中的哪些变量名 
    skiprows:数据读取时,指定需要跳过原数据集开头的行数
             有一些表格开头是有几行文字说明的,读取的时候应该跳过
    skipfooter:数据读取时,指定需要跳过原数据集末尾的行数 
    converters:用于数据类型的转换(以字典的形式指定) 
    encoding:如果文件中含有中文,有时需要指定字符编码

    举例:

    import pandas as pd
    #  读取文本文件和CSV,空白行自动过滤
    df1 = pd.read_csv(r'data_test01.txt',
                      # 读取数据时跳过开头2行
                     skiprows=2,
                      # 读取数据时跳过末尾3行
                      skipfooter=3,
                      # 指定字符编码
                      encoding='utf8',
                      # 不将第1行作为列名
                      header = None,
                      # 自定义列名
                      names = ['id','year','month','day','gender','occupation','income'],
                      # 声明数据类型
                      converters = {'id':str},
                      #将指定千分位在这个表格里用什么表示,移除千分位符号
                      thousands='&',
                      usecols=['occupation','income']
                     )
    df1

    5.2数据读取之read_excel

    # excel表格读取
    pd.read_excel(io, sheetname=0, header=0, skiprows=None, skip_footer=0, index_col=None, names=None,
    na_values=None, thousands=None, convert_float=True)
    
    io:指定电子表格的具体路径 
    sheetname:指定需要读取电子表格中的第几个Sheet,既可以传递整数也可以传递具体的Sheet名称 
    header:是否需要将数据集的第一行用作表头,默认为是需要的 
    skiprows:读取数据时,指定跳过的开始行数
    skip_footer:读取数据时,指定跳过的末尾行数 
    index_col:指定哪些列用作数据框的行索引(标签)
    na_values:指定原始数据中哪些特殊值代表了缺失值 
    thousands:指定原始数据集中的千分位符 
    convert_float:默认将所有的数值型字段转换为浮点型字段 
    converters:通过字典的形式,指定某些列需要转换的形式
    # 读取xls,xlsx表格文件
    df2 = pd.read_excel(r'data_test02.xlsx',
                       header= None,
                        names =['id','class','color','count'],
                        converters = {'id':str},
                       )
    df2.index
    df2.columns
    df2['class']  # class是关键字
    df2.color
    df2

    5.3 数据读取之read_sql

    # # 读取关系型数据库表数据
    '''
    在notebook内如何下载第三方模块
    !pip install pymysql
    '''
    # 在anaconda环境下直接安装模块
    !conda install pymysql
    # pymysql模块
    import pymysql
    conn = pymysql.connect(host,port,user,password, database, charset)
    
    host:指定需要访问的MySQL服务器
    port:指定访问MySQL数据库的端口号 charset:指定读取MySQL数据库的字符集,如果数据库表中含有中文,一般可以尝试将该参数设置为 “utf8”或“gbk”
    user:指定访问MySQL数据库的用户名
    password:指定访问MySQL数据库的密码
    database:指定访问MySQL数据库的具体库名
      
    # 利用pymysql创建好链接MySQL的链接之后即可通过该链接操作MySQL
    pd.read_sql('select * from user', con = conn)
    conn.close()  # 关闭链接

    5.4 网页数据获取read_html

    # read_html可以直接获取到页面上table标签里的数据
    res = pd.read_html('https://baike.baidu.com/item/NBA%E6%80%BB%E5%86%A0%E5%86%9B/2173192?fr=aladdin')
    res

    6.DataFrame数据概览

    import pandas as pd
    df3 = pd.read_csv(r'sec_cars.csv')
    df3.index
    df3.columns
    df3.shape  # 元组(行数,列数)
    df3.dtypes # 每个字段存储的数据类型
    df3.describe() # 快速统计
    df3.head() # 默认前5行
    df3.tail(5) #默认后5行

    6.1 数据概览之行列操作

    # 修改列名称
    df3.rename(columns={'Brand':'品牌'})
    # 创建列
    df3['haha']= 666
    # 删除列
    df3.drop(columns=['haha',],axis=1,inplace=True)
    # 自定义列位置
    # df3.insert(0,'NB',123)
    # df3.insert(0,'计算',df3['Km(W)']*df3['Sec_price'])
    df3.drop(columns=['计算','NB'],axis=1,inplace=True)

    6.2 数据筛选

    # 获取指定列的数据
    #指定单列数据
    # df3['Name']
    # 方式二:一定要避免与关键字和内置方法名冲突
    # df3.Name
    # 获取多列数据
    df3[['Name','Sec_price']]
    
    
    # 获取行数据
    df3[0:10]
    # 1.获取brand是众泰的
    df3.loc[df3['Brand']=='众泰',]
    # 2.获取brand是DS并且Discharge是国4 的
    df3.loc[(df3['Brand']=='DS')&(df3['Discharge']=='国4')]
    # 3.获取brand是众泰并且Discharge是国4 的数据的车名和新车价格
    df3.loc[(df3['Brand']=='众泰') & (df3['Discharge']=='国4'),['Name','New_price']]
    """知识回顾:逻辑运算符链接条件 条件最好用括号括起来"""

    6.3 数据处理

    # 1.日期处理:2021年1月25日转为 2021-1-25
    # 日期类型转换
    df3['Boarding_time'] = pd.to_datetime(df3['Boarding_time'], format = '%Y年%m月')
    
    # 2.字符串转数字:利用字符串切片:22.95万 -->22.95
    # .astype转换类型
    df3['New_price']= df3['New_price'].str[:-1].astype('float')
    # 3.判断数据是否重复并进行处理
    df4=pd.read_excel(r'data_test04.xlsx') df4.head() # 判断数据是否重复,如果想单独判断某列是否有重复需要加参数subset df4.duplicated() # 针对重复数据进行删除 df4.drop_duplicates()

    6.4 异常值识别与处理

    异常值的识别与处理
    1. Z得分法
    2. 分位数法
    3. 距离法

    缺失值处理:

    缺失值的识别与处理
    1. df.isnull
    2. df.fillna
    3. df.dropna


    data05 = pd.read_excel(r'data_test05.xlsx') # data05.isnull() # 默认整体挨个判断是否缺失 data05.isnull().any() # 可以看那几个字段有缺失数据 # 计算缺失数据的比例 data05.isnull().sum(axis = 0)/data05.shape[0] # uid 0.0 # regit_date 0.0 # gender 0.1 # age 0.3 # income 0.2 # dtype: float64 """ 针对缺失数据: 1.删除缺失数据(要看缺失比例) 2.填充(根据不同的数据采用不能的填充策略) 1.针对收入采用中位数 2.年龄采用平均数(男均和女均) 3.针对性别采用众数 4. k近龄 """ data05.fillna(value = { 'gender':data05.gender.mode()[0], # 众数:可以有一个也可能是多个 'age':data05.age.mean(), # 平均值 'income':data05.income.median() # 中位数 }, inplace = True)

    6.5.数据透视表

    # 透视表功能
    pd.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
    
    data:指定需要构造透视表的数据集 
    values:指定需要拉入“数值”框的字段列表
    index:指定需要拉入“行标签”框的字段列表 
    columns:指定需要拉入“列标签”框的字段列表 
    aggfunc:指定数值的统计函数,默认为统计均值,也可以指定numpy模块中的其他统计函数 
    
    fill_value:指定一个标量,用于填充缺失值 
    margins:bool类型参数,是否需要显示行或列的总计值,默认为False 
    dropna:bool类型参数,是否需要删除整列为缺失的字段,默认为True 
    margins_name:指定行或列的总计名称,默认为All
    
    例如: data06
    = pd.read_csv(r'diamonds.csv') data06.shape data06.head() pd.pivot_table(data06, index = 'color', values='price', aggfunc='mean') pd.pivot_table(data06, index = 'color', columns='clarity', values='price', aggfunc='size')

    6.6 分组与聚合

    import numpy as np
    # 单个字段分组  .groups直接输出结果
    # data06.groupby(by = ['color']).groups
    # 通过groupby方法,指定分组变量,先按颜色color分组,再按切片分组
    grouped = data06.groupby(by = ['color','cut'])
    # 对分组变量进行统计汇总
    result = grouped.aggregate({'color':np.size, 'carat':np.min, 
                                'price':np.mean, 'table':np.max})
    
    # 调整字段变量名的顺序
    result = pd.DataFrame(result, columns=['color','carat','price','table'])
    
    # 数据集重命名
    result.rename(columns={'color':'counts',
                           'carat':'min_weight',
                           'price':'avg_price',
                           'table':'max_table'}, 
                  inplace=True)

    实战练习

    # 分析NBA各球队冠军次数及球员FMVP次数

    res = pd.read_html('https://baike.baidu.com/item/NBA%E6%80%BB%E5%86%A0%E5%86%9B/2173192?fr=aladdin')  ### 返回的是一个列表  列表中是当前页面的所有表格数据
    type(res)
    res
    
    # 获取有效数据
    champion = res[0]
    champion
    
    # 针对冠军字段分组
    #
    ch.groupby(['冠军']).aggregate({'冠军':np.size}).rename(columns={'冠军':"次数"})
    champion.groupby('冠军').groups
    # 获取分组之后的各分组大小 champion.groupby('冠军').size() # 获取各组冠军次数 champion.groupby('冠军').size().sort_values(ascending=False) # 升序 # 分组字段可以一次性取多个 champion.groupby(['冠军', 'FMVP']).size()

    6.7 数据合并

    # 纵向合并
    pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None) objs:指定需要合并的对象,可以是序列、数据框或面板数据构成的列表 axis:指定数据合并的轴,默认为0,表示合并多个数据的行,如果为1,就表示合并多个数据的列 join:指定合并的方式,默认为outer,表示合并所有数据,如果改为inner,表示合并公共部分的数据 join_axes:合并数据后,指定保留的数据轴 ignore_index:bool类型的参数,表示是否忽略原数据集的索引,默认为False,如果设为True,就表示忽略原索引并生成新索引 keys:为合并后的数据添加新索引,用于区分各个数据部分
    # 构造数据集df1和df2
    df1 = pd.DataFrame({
      'name':['张三','李四','王二'], 
      'age':[21,25,22], 
      'gender':['','','']}
    )
    df2 = pd.DataFrame({
      'name':['丁一','赵五'], 
      'age':[23,22], 
      'gender':['','']}
    )
    # 1.数据集的纵向合并
    pd.concat([df1,df2] , keys = ['df1','df2'])  # 加keys参数可以在合并之后看到数据来源
    
    # 重置数据的行索引:reset_index() 
    pd.concat([df1,df2] , keys = ['df1','df2']).reset_index() 
    # 删除数据的老索引
    pd.concat([df1,df2] , keys = ['df1','df2']).reset_index().drop(labels ='level_1', axis = 1).rename(columns = {'level_0':'Class'})
    
    # 如果df2数据集中的“姓名变量为Name”
    # 列名不一致会导致多出一列,并且出现NaN数据
    df2 = pd.DataFrame({
      'Name':['丁一','赵五'], 
      'age':[23,22], 
      'gender':['','']}
    )
    # 数据集的纵向合并
    pd.concat([df1,df2])
    # concat行合并,数据源的变量名称要完全相同(变量名顺序没有要求)


    2.数据的横向合并
    pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'))
    
    left:指定需要连接的主 right:指定需要连接的辅表
    how:指定连接方式,默认为inner内连,还有其他选项,如左连left、右连right和外连outer on:指定连接两张表的共同字段
    left_on:指定主表中需要连接的共同字段
    right_on:指定辅表中需要连接的共同字段 
    left_index:bool类型参数,是否将主表中的行索引用作表连接的共同字段,默认为False right_index:bool类型参数,是否将辅表中的行索引用作表连接的共同字段,默认为False sort:bool类型参数,是否对连接后的数据按照共同字段排序,默认为False 
    suffixes:如果数据连接的结果中存在重叠的变量名,则使用各自的前缀进行区分
    # 数据的横向合并(inner/left/right join)
    # 构造数据集
    df3 = pd.DataFrame({
      'id':[1,2,3,4,5],
      'name':['张三','李四','王二','丁一','赵五'],
      'age':[27,24,25,23,25],
      'gender':['','','','','']})
    df4 = pd.DataFrame({
      'Id':[1,2,2,4,4,4,5], 
      'score':[83,81,87,75,86,74,88], 
      'kemu':['科目1','科目1','科目2','科目1','科目2','科目3','科目1']})
    df5 = pd.DataFrame({
      'id':[1,3,5],
      'name':['张三','王二','赵五'],
      'income':[13500,18000,15000]})
    
    # 首先df3和df4连接
    merge1 = pd.merge(left = df3, 
                      right = df4, 
                      how = 'left', 
                      left_on='id', 
                      right_on='Id')
    # 再将连接结果与df5连接
    merge2 = pd.merge(left = merge1, 
                      right = df5, 
                      how = 'left')
  • 相关阅读:
    LeetCode Best Time to Buy and Sell Stock
    LeetCode Scramble String
    LeetCode Search in Rotated Sorted Array II
    LeetCode Gas Station
    LeetCode Insertion Sort List
    LeetCode Maximal Rectangle
    Oracle procedure
    浏览器下载代码
    Shell check IP
    KVM- 存储池配置
  • 原文地址:https://www.cnblogs.com/yangmeichong/p/14325004.html
Copyright © 2011-2022 走看看