【读书笔记】《利用Python进行数据分析》第2版_第六章 数据载入、存储及文件格式

6.1 文本格式数据的读写

  • 将表格型数据读取为DataFrame对象:read_csv()和read_table()

  • Pandas的解析函数

    img
    • 可选参数

      • 索引:可以将一或多个列作为返回的DataFrame
      • 类型推断和数据转换:包括用户自定义的值转换和自定义的缺失值符号列表。
      • 日期时间解析:包括组合功能,包括将分散在多个列上的日期和时间信息组合成结果中的单个列
      • 迭代:对大型文件的分块迭代
      • 未清洗数据问题:跳过行、页脚、注释以及其他次要数据,比如使用逗号分隔千位的数字。
    • 一些数据载入函数(如pandas.read_csv等)会进行类型推断,因为列的数据类型并不是数据格式的一部分,不必指定那一列是数值、整数、布尔值或字符串。

      • 处理日期自定义类型数据需要其他努力

        • pandas默认分配列名,也可以自己指定列名:pd.read_csv(‘examples/ex2.csv’,names=[‘a’,’b’,’c’,’d’,’message’])

        • 将message列成为DataFrame索引,可以指定位置4的列为索引,或将‘message’传给参数index_col

          names = ['a', 'b', 'c', 'd', 'message']
          pd.read_csv('examples/ex2.csv', names=names, index_col='message')
          
        • 从多个列形成分层索引:传入一个包含列序号或列名的列表:pd.read_csv(‘examples/csv_mindex.cav’,index_col=[‘key1’,’key2’])

      • 表的分隔符不固定,使用空白或其他方式来分隔字段

        • 向read_table传入一个正则表达式作为分隔符

          result = pd.read_table('examples/ex3.txt',sep='\s+')
          
      • 使用skiprows来跳过某些行(例:第一行、第三行和第四行)

        pd.read_csv('examples/ex4.csv',skiprows=[0,2,3])
        
  • 缺失值处理

    • 缺失值不显示(空字符串)或用标识值显示(NA和Null等)

    • na_values选项可以传入一个列表一组字符串来处理缺失值

      pd.read_csv('examples/ex5.csv',na_values=['NULL'])
      
    • 在字典中,每列可以指定不同的缺失值标识

      sentinels = {'message': ['foo', 'NA'], 'something':['two']}
      pd.read_csv('examples/ex5.csv', na_values=sentinels)
      
  • 一些read_csv/read_table函数常用参数

    img

分块读入文本文件

处理大型文件时,常需要读入文件的一个小片段或者按小块遍历文件

  • 在尝试大文件前,可先对pandas的显示设置进行调整,使之更为紧凑

    pd.options.display.max_rows = 10
    # 只读取文件的前五行
    result = pd.read_csv('examples/ex6.csv',nrows=5)
    
  • 设置chunksize指定每个分块的行数

    chunker = pd.read_csv('examples/ex6.csv',chunksize=1000)
    
  • read_csv返回TextParser对象,可根据chunksize遍历文件

    # 遍历ex6.csv,并对’key’列聚合获得计数值
    chunker = pd.read_csv('examples/ex6.csv',chunksize=1000)
    tot = pd.Series([])
    for piece in chunker:
        tot = tot.add(piece['key'].value_counts(),fill_value=0)
    tot = tot.sort_values(ascending=False)
    
  • TextParser还具有get_chunk方法,允许你按照任意大小读取数据块

将数据写入文本格式

  • DataFrame的to_csv方法:将数据导出为逗号分隔的文件,可以通过sep设置其他分隔符
    • 缺失值在输出时以空字符串出现,也可以用其他标识符对缺失值进行标注:data.to_csv(sys.stdout,na_rep=‘NULL’)
    • 默认列和标签都会被写入,可以禁止二者写入:data.to_csv(sys.stdout,index=False,header=False)
    • 按照指定顺序写入列的子集:data.to_csv(sys.stdout,index=False,columns=[‘a’,’b’,’c’])
    • Series也有to_csv方法

使用分隔格式

  • read_table无法接收一个带有一行或多行错误的文件

  • image-20220328231634813
  • 使用Python的csv模块处理带有单字符分隔符的文件,将打开的文件型对象传给csv.reader

    import csv
    f = open('examples/ex7.csv')
    reader = csv.reader(f)
    # 像遍历文件一样,遍历reader会产生元组
    for line in reader:
        print(line)  # 元组的值为删除了引号的字符
        
    # 将文件读取为行的列表
    with open('examples/ex7.csv') as f:
        lines = list(csv.reader(f))
    # 将数据拆分为列名行和数据行
    header,values = lines[0],lines[1:]
    # 使用字典推导式和表达式zip(*values)生成一个包含数据列的字典,字典中行转置成列
    data_dict = {h: v for h,v in zip(header,zip(*values))}
    data_dict
    # {'a': ('1', '1'), 'b': ('2', '2'), 'c': ('3', '3')}
    
  • 使用csv.Dialect定义子类处理不同风格的文件,比如不同的分隔符、字符串引用约定或行终止符等

    class my_dialect(csv.Dialect):
        lineterminator = '\n'
        delimiter = ';'
        quotechar = '"'
        quoting = csv.QUOTE_MINIMAL
    reader = csv.reader(f,dialect=my_dialect)
    
    # 不定义子类,直接将CSV方言参数传入csv.reader的关键字参数
    reader = csv.reader(f,delimiter='|')
    

    csv.Dialect中的一些属性及其用途

    img

  • 对于具有更复杂或固定的多字符分隔符的文件,你将无法使用csv模块.

    使用字符串的split方法或正则表达式方法re.split进行拆分和其他清理工作

  • 使用csv.writer手动写入被分隔的文件

    • 接收 一个已打开可写入文件对象 和 csv.reader相同的CSV方言、格式选项
    • image-20220328233731729

JSON数据

JSON(JavaScript Object Notation的简写)已经成为Web浏览器和其他应用间通过HTTP请求发送数据的标准格式。

  • 除空值null和一些细微差别(例如不允许列表末尾的逗号)之外,JSON非常接近Python。

    • 基本类型是对象(字典)、数组(列表)、字符串、数字、布尔值和空值
    • 所有都必须是字符串
  • JSON字符串和Python互相转换

    • json.loads方法将JSON字符串转换为Python形式

      obj = """
      {"name": "Wes",
       "places_lived": ["United States", "Spain", "Germany"],
       "pet": null,
       "siblings": [{"name": "Scott", "age": 30, "pets": ["Zeus", "Zuko"]},
                    {"name": "Katie", "age": 38,
                     "pets": ["Sixes", "Stache", "Cisco"]}]
      }
      """
      import json
      result = json.loads(obj)
      result
      """
      {'name': 'Wes',
       'places_lived': ['United States', 'Spain', 'Germany'],
       'pet': None,
       'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']},
        {'name': 'Katie', 'age': 38, 'pets': ['Sixes', 'Stache', 'Cisco']}]}
      """
      
    • json.dumps可以将Python对象转换回JSON:

      asjson = json.dumps(result)
      
  • 将JSON转换成其他数据结构,方便的是将字典构成的列表(之前是JSON对象)传入DataFrame构造函数,并选出数据字段的子集

    • import pandas as pd
      siblings = pd.DataFrame(result['siblings'], columns=['name', 'age'])
      siblings
      """
      name	age
      0	Scott	30
      1	Katie	38
      """
      
    • pandas.read_json可以自动将JSON数据集按照指定次序转换为Series或DataFrame。

      • pandas.read_json默认JSON数组中的每个对象是表里的一行
  • 从pandas中将数据导出为JSON,对Series和DataFrame使用to_json方法

XML和HTML:网络抓取

Python有很多针对HTML和XML格式进行读取、写入数据的库

lxml(http://lxml.de)、Beautiful Soup、html5lib

lxml更快,其他库操作更多

html

  • pandas的内建函数read_html可以使用lxml和BeautifulSoup等库将HTML中的表自动解析为DataFrame对象

    • 安装

      conda install lxml
      pip install beautifulsoup4 html5lib
      
  • pandas.read_html函数存在很多选项,默认搜索并尝试解析所有包含在

    标签中的表格型数据,返回的结果是DataFrame对象的列表

  • 举例:从美国FDIC政府机构下载了显示银行倒闭数据的HTML文件(在pandas文档中使用)

    tables = pd.read_html('examples/fdic_failed_bank_list.html')
    len(tables) # 1
    failures = tables[0] 
    failures.head()
    # failures有很多列,pandas在行内插入了换行符\
    # 计算每年银行倒闭的数量
    close_timestamps = pd.to_datetime(failures['Closing Date'])
    close_timestamps.dt.year.value_counts()
    

使用lxml.objectify解析XML

XML(eXtensible Markup Language)是结构化数据格式,它使用元数据支持分层、嵌套数据。

示例背景:纽约大都会交通局(MTA)发布了一份关于其公交、火车服务(http://www.mta.info/developers/down loadhtml)的数据集。每个火车或公交服务都有一个不同的文件(例如Performance_MNR.xml代表地铁-北铁路),文件中以一系列XML记录的方式包含了按月的数据。

  • 使用lxml.objectify解析文件,用getroot获得XML文件根节点的引用

    from lxml import objectify
    path = 'datasets/mta_perf/Performance_MNR.xml'
    parsed = objectify.parse(open(path))
    root= parsed.getroot()
    
  • root.INDICATOR返回一个生成器,可以产生每一个XML元素

    # root.INDICATOR返回一个生成器,可以产生每一个<INDICATOR>XML元素(不包括几个标签)
    data = []
    
    skip_fields = ['PARENT_SEQ', 'INDICATOR_SEQ',
                   'DESIRED_CHANGE', 'DECIMAL_PLACES']
    
    for elt in root.INDICATOR:
        el_data = {}
        for child in elt.getchildren():
            if child.tag in skip_fields:
                continue
            el_data[child.tag] = child.pyval
        data.append(el_data)
    
  • XML标签可以更复杂,每个标签可以包含元数据。一个HYML连接标签,也是有效的XML

    from io import StringIO
    tag = '<a href="http://www.google.com">Google</a>'
    root = objectify.parse(StringIO(tag)).getroot()
    # 现在可以访问标签或链接文本中的任何字段(如href)
    root # <Element a at 0x7f6b15817748>
    root.get('href') # 'http://www.google.com'
    root.text # 'Google'
    

6.2 二进制格式

pickle

  • 使用Python内建的pickle序列化模块进行二进制格式操作

    • pandas对象使用to_pickle方法将数据以pickle格式写入硬盘

      frame = pd.read_csv('examples/ex1.csv')
      frame.to_pickle('examples/frame_pickle')
      
    • 使用pandas.read_pickle

      pd.read_pickle('examples/frame_pickle')
      
    • pickle仅作为短期存储来使用,被pickle化的对象可能因为库版本更新而无法反序列化

  • Python支持的其他两个二进制格式:HDF5和MessagePack

  • pandas或NumPy其他存储格式

    • bcolz(http://bcolz.blosc.org/):基于Blosc压缩库的可压缩列式二进制格式
    • 基于Blosc压缩库的可压缩列式二进制格式
    • R编程社区的Hadley Wickham(http://hadley.nz/)设计的跨语言列式文件格式
    • Feather使用Apache箭头(http://arrow.apache.org)列式存储器格式

使用HDF5格式

存储大量的科学数组数据,以C库的形式提供,有很多其他语言接口

用于处理不适合在内存中存储的超大型数据,可以仅高效读写一小块

  • “HDF”代表分层数据格式,每个HDF5文件可以存储多个数据集并且支持元数据。

  • HDF5支持多种压缩模式的即时压缩,重复模式的数据可以更高效地存储

  • 可使用PyTables或h5py等库直接访问HDF5文件,但pandas提供高阶接口:HDFStore类,可以像字典一样处理细节,简化Series和DataFrame的存储。

    frame = pd.DataFrame({'a': np.random.randn(100)})
    store = pd.HDFStore('mydata.h5')
    store['obj1'] = frame
    store['obj1_col'] = frame['a']
    store
    
    • 包含在HDF5文件中的对象可以用字典型API进行检索

    • HDFStore支持两种存储模式,‘fixed’和’table’(后者更慢,但支持一种特殊语法的查询操作)

      # put是store ['obj2']=frame方法的显式版本,但允许我们设置其他选项,如存储格式
      store.put('obj2', frame, format='table')
      store.select('obj2', where=['index >= 10 and index <= 15'])
      store.close()
      
    • pandas.read_hdf函数可以用作快捷方法

      frame.to_hdf('mydata.h5', 'obj3', format='table')
      pd.read_hdf('mydata.h5', 'obj3', where=['index < 5'])
      
  • 处理远程服务器上的数据时,使用专门为分布式存储而设计的二进制格式更为合适,比如Apache Parquet(http://parquet.apache.org)。

  • 处理大量本地数据时,尝试使用PyTables和h5py。

  • 很多数据分析的困难在于I/O密集(而不是CPU密集),使用类似HDF5可以加速

HDF5并不是数据库,它是一种适合一次写入多次读取的数据集.

多个写入者持续写入,文件可能会损坏

读取Microsoft Excel文件

pandas也支持通过ExcelFile类或pandas.read_excel函数来读取存储在Excel表格型数据

使用附加包xlrd和openpyxl来分别读取XLS和XLSX文件的

  • 通过将xls或xlsx的路径传入ExcelFile,生成一个实例。

    xlsx = pd.ExcelFile('examples/ex1.xlsx')
    
  • 表格数据可以通过pandas.read_excel读取到DataFrame中

    pd.read_excel(xlsx, 'Sheet1')
    
  • 含有多个表的文件,生成ExcelFile更快,但也可以更简便地将文件名传入pandas.read_excel

    frame = pd.read_excel('examples/ex1.xlsx', 'Sheet1')
    frame
    
  • 将pandas数据写入到Excel格式中

    • 先生成一个ExcelWriter
    • 使用pandas对象的to_excel方法将数据写入
    writer = pd.ExcelWriter('examples/ex2.xlsx')
    frame.to_excel(writer, 'Sheet1')
    writer.save()
    
    • 也可以将文件路径传给to_excel,避免直接调用ExcelWriter
    frame.to_excel('examples/ex2.xlsx')
    

6.3 与Web API交互

使用requests包(http://docs.python-requests.orgt)与Web API交互更简单

获取GitHub上最新的30条关于pandas的问题

  • 用附加库requests发送一个HTTP GET请求

    import requests
    url = 'https://api.github.com/repos/pandas-dev/pandas/issues'
    resp = requests.get(url)
    resp
    
  • Response(响应)对象的json方法将返回一个包含解析为本地Python对象的JSON的字典

    # data中的每个元素都是一个包含GitHub问题页面上的所有数据的字典(注释除外)
    data = resp.json()
    data[0]['title']
    
  • 将data直接传给DataFrame,并提取感兴趣的字段

    issues = pd.DataFrame(data, columns=['number', 'title',
                                         'labels', 'state'])
    issues
    

6.4 与数据库交互

业务场景中,基于SQL的关系型数据库(例如SQL Server、PostgreSQL和MySQL)使用广泛

pandas很多函数可以从SQL中将数据读取为DataFrame

SQLAlchemy项目(http://www.sqlalchemy.org/)是一个流行的PythonSQL工具包,抽象去除了SQL数据库之间的许多常见差异。

  • 使用Python内建的sqlite3驱动来生成一个SQLite数据库

    import sqlite3
    query = """
    CREATE TABLE test
    (a VARCHAR(20), b VARCHAR(20),
     c REAL,        d INTEGER
    );"""
    con = sqlite3.connect('mydata.sqlite')
    con.execute(query)
    con.commit()
    
  • 插入几行数据

    data = [('Atlanta', 'Georgia', 1.25, 6),
            ('Tallahassee', 'Florida', 2.6, 3),
            ('Sacramento', 'California', 1.7, 5)]
    stmt = "INSERT INTO test VALUES(?, ?, ?, ?)"
    con.executemany(stmt, data)
    con.commit()
    
  • 大部分Python的SQL驱动(PyODBC、psycopg2、MySQLdb、pymssql等)返回的是元组的列表

    cursor = con.execute('select * from test')
    rows = cursor.fetchall()
    rows
    
  • 将元组的列表传给DataFrame构造函数,要包含在游标的description属性中的列名

    cursor.description
    pd.DataFrame(rows, columns=[x[0] for x in cursor.description])
    
  • pandas中read_sql函数可以从通用的SQLAlchemy连接中轻松地读取数据

    # 使用SQLAlchemy连接到相同的SQLite数据库,并从之前创建的表中读取数据
    import sqlalchemy as sqla
    db = sqla.create_engine('sqlite:///mydata.sqlite')
    pd.read_sql('select * from test', db)
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值