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')
  • 相关阅读:
    从操作系统拖拽图片到指定区域进行预览
    原生拖拽,拖放事件(drag and drop)
    H5原生拖拽事件
    css3滚动提示
    通过模糊来弱化背景
    js获取url的各项参数
    垂直居中 解决方法
    紧贴底部的页脚
    实现html元素跟随touchmove事件的event.touches[0].clientX移动
    前端方面值得尊敬的大神们
  • 原文地址:https://www.cnblogs.com/yangmeichong/p/14325004.html
Copyright © 2011-2022 走看看