大神是这样处理 CSV 数据的

简介: 大神是这样处理 CSV 数据的


阅读本文大概需要 5.5 分钟。


读写 CSV 数据

问题 


你想读写一个 CSV 格式的文件


解决方案


对于大多数的 CSV 格式的数据读写问题,都可以使用 csv 库。例如:假设你在一 个名叫 stocks.csv 文件中有一些股票市场数据,像这样:


Symbol,Price,Date,Time,Change,Volume
"AA",39.48,"6/11/2007","9:36am",-0.18,181800
"AIG",71.38,"6/11/2007","9:36am",-0.15,195500
"AXP",62.58,"6/11/2007","9:36am",-0.46,935000
"BA",98.31,"6/11/2007","9:36am",+0.12,104800
"C",53.08,"6/11/2007","9:36am",-0.25,360900
"CAT",78.29,"6/11/2007","9:36am",-0.23,225400


下面向你展示如何将这些数据读取为一个元组的序列:


import csv
with open('stocks.csv') as f:
    f_csv = csv.reader(f)
    headers = next(f_csv)
    for row in f_csv:
      pass

在上面的代码中,row 会是一个列表。因此,为了访问某个字段,你需要使用下标, 如 row[0] 访问 Symbol,row[4] 访问 Change。由于这种下标访问通常会引起混淆,你可以考虑使用命名元组


例如:

    from collections import namedtuple
    with open('stock.csv') as f:
      f_csv = csv.reader(f)
      headings = next(f_csv)
      Row = namedtuple('Row', headings)
      for r in f_csv:
        row = Row(*r)

    它允许你使用列名如 row.Symbol 和 row.Change 代替下标访问。需要注意的是这 个只有在列名是合法的 Python 标识符的时候才生效。如果不是的话,你需要修改下原始的列名 (如将非标识符字符替换成下划线之类的)。另外一个选择就是将数据读取到一个字典序列中去。

    可以这样做

      import csv
      with open('stocks.csv') as f:
        f_csv = csv.DictReader(f)
        for row in f_csv:
          # process row

      在这个版本中,你可以使用列名去访问每一行的数据了。

      比如,row['Symbol'] 或 者 row['Change'] 为了写入 CSV 数据,你仍然可以使用 csv 模块,不过这时候先创建一个 writer 对象

      例如:

        headers = ['Symbol','Price','Date','Time','Change','Volume']
        rows = [('AA', 39.48, '6/11/2007', '9:36am', -0.18, 181800),
        ('AIG', 71.38, '6/11/2007', '9:36am', -0.15, 195500),
        ('AXP', 62.58, '6/11/2007', '9:36am', -0.46, 935000),
        ]
        with open('stocks.csv','w') as f:
          f_csv = csv.writer(f)
          f_csv.writerow(headers)
          f_csv.writerows(rows)

        如果你有一个字典序列的数据,可以像这样做


        headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume']
        rows = [{'Symbol':'AA', 'Price':39.48, 'Date':'6/11/2007',
        'Time':'9:36am', 'Change':-0.18, 'Volume':181800},
        {'Symbol':'AIG', 'Price': 71.38, 'Date':'6/11/2007',
        'Time':'9:36am', 'Change':-0.15, 'Volume': 195500},
        {'Symbol':'AXP', 'Price': 62.58, 'Date':'6/11/2007',
        'Time':'9:36am', 'Change':-0.46, 'Volume': 935000},
        ]
        with open('stocks.csv','w') as f:
          f_csv = csv.DictWriter(f, headers)
          f_csv.writeheader()
          f_csv.writerows(rows)


        讨论


        你应该优先选择 CSV 模块分割或解析 CSV 数据。


        例如,你可能会像编写类似 下面这样的代码


        with open('stocks.csv') as f:
          for line in f:
          row = line.split(',')

        使用这种方式的一个缺点就是你仍然需要去处理一些棘手的细节问题

        比如,如果 某些字段值被引号包围,你不得不去除这些引号。另外,如果一个被引号包围的字段碰巧含有一个逗号,那么程序就会因为产生一个错误大小的行而出错。

        默认情况下,csv 库可识别 Microsoft Excel 所使用的 CSV 编码规则。这或许也是 最常见的形式,并且也会给你带来最好的兼容性。然而,如果你查看 csv 的文档,就会 发现有很多种方法将它应用到其他编码格式上 (如修改分割字符等)。

        例如,如果你想 读取以 tab 分割的数据,可以这样做:


        with open('stock.tsv') as f:
        f_tsv = csv.reader(f, delimiter='\t')
        for row in f_tsv:
          pass

        如果你正在读取 CSV 数据并将它们转换为命名元组,需要注意对列名进行合法性 认证。例如,可以像下面这样在非法标识符上使用 一个正则表达式替换:

          import re
          with open('stock.csv') as f:
          f_csv = csv.reader(f)
          headers = [ re.sub('[^a-zA-Z_]', '_', h) for h in next(f_csv) ]
          Row = namedtuple('Row', headers)
          for r in f_csv:
            row = Row(*r)
          


          还有重要的一点需要强调的是,csv 产生的数据都是字符串类型的,它不会做任何 其他类型的转换。如果你需要做这样的类型转换,你必须自己手动去实现。

          下面是一个 在 CSV 数据上执行其他类型转换的例子:

            col_types = [str, float, str, str, float, int]
            with open('stocks.csv') as f:
              f_csv = csv.reader(f)
              headers = next(f_csv)
              for row in f_csv:
                row = tuple(convert(value) for convert, value in zip(col_types, row))


            通常来讲,可能并不想过多去考虑这些转换问题。在实际情况中,CSV 文件都 或多或少有些缺失的数据,被破坏的数据以及其它一些让转换失败的问题。因此,除非 你的数据确实有保障是准确无误的,否则你必须考虑这些问题 (你可能需要增加合适的 错误处理机制)

            最后,如果你读取 CSV 数据的目的是做数据分析和统计的话,你可能需要看一看 Pandas 包。Pandas 包含了一个非常方便的函数叫 pandas.read_csv() ,它可以加载 CSV 数据到一个 DataFrame 对象中去。然后利用这个对象你就可以生成各种形式的统 计、过滤数据以及执行其他高级操作了。

            目录
            打赏
            0
            0
            0
            0
            4
            分享
            相关文章
            MQTT的奇妙之旅:探索RabbitMQ Web MQTT插件的威力【RabbitMQ 十一】
            MQTT的奇妙之旅:探索RabbitMQ Web MQTT插件的威力【RabbitMQ 十一】
            301 0
            MongoDB compact 命令详解
            为什么需要 compact 一图胜千言 remove 与 drop 的区别 MongoDB 里删除一个集合里所有文档,有两种方式 db.collection.remove({}, {multi: true}),逐个文档从 btree 里删除,最后所有文档被删除,但文件物理空间不会被回收 db.
            Vitepress初始化配置的样式,写法,序,文本,vitepress乱序的问题,vitepress的index.md文件没有出现的问题如何解决,细节问题,----必须带
            Vitepress初始化配置的样式,写法,序,文本,vitepress乱序的问题,vitepress的index.md文件没有出现的问题如何解决,细节问题,----必须带
            Pandas 2.2 中文官方教程和指南(九·二)(3)
            Pandas 2.2 中文官方教程和指南(九·二)
            87 0
            分钟级实时数据分析的背后——实时湖仓产品解决方案
            袋鼠云在结合当前数据湖技术的基础上,建设实时湖仓平台,满足客户“快、精、准”的数据需求。本文将详细介绍实时湖仓产品解决方案,让企业能够更专注地去解决他们的业务价值。
            229 0
            带你读《云原生机密计算最佳实践白皮书》——Intel TDX机密容器(3)
            带你读《云原生机密计算最佳实践白皮书》——Intel TDX机密容器(3)
            297 0
            带你读《卫星互联网:助力新基建的有硬科技》——5. 地面5G移动通信网与卫星互联网
            带你读《卫星互联网:助力新基建的有硬科技》——5. 地面5G移动通信网与卫星互联网
            LeetCode 104. 二叉树的最大深度
            给定一个二叉树,找出其最大深度。
            130 0
            ZYNQ - 嵌入式Linux开发 -01- shell操作和文件系统
            ZYNQ - 嵌入式Linux开发 -01- shell操作和文件系统
            352 0
            ZYNQ - 嵌入式Linux开发 -01- shell操作和文件系统
            AI助理

            你好,我是AI助理

            可以解答问题、推荐解决方案等

            登录插画

            登录以查看您的控制台资源

            管理云资源
            状态一览
            快捷访问