【问题标题】:Parse CSV file and modify columns解析 CSV 文件并修改列
【发布时间】:2016-01-05 20:23:29
【问题描述】:

我想以特定方式更改 CSV 文件。这是我的示例 CSV 文件:

name,time,Operations
Cassandra,2015-10-06T15:07:22.333662984Z,INSERT
Cassandra,2015-10-06T15:07:24.334536781Z,INSERT
Cassandra,2015-10-06T15:07:27.339662984Z,READ
Cassandra,2015-10-06T15:07:28.344493608Z,READ
Cassandra,2015-10-06T15:07:28.345221189Z,READ
Cassandra,2015-10-06T15:07:29.345623750Z,READ
Cassandra,2015-10-06T15:07:31.352725607Z,UPDATE
Cassandra,2015-10-06T15:07:33.360272493Z,UPDATE
Cassandra,2015-10-06T15:07:38.366408708Z,UPDATE

我知道如何使用 python 解析器读取 CSV 文件,但我完全是初学者。我需要得到这样的输出:

start_time,end_time,operation
2015-10-06T15:07:22.333662984Z,2015-10-06T15:07:24.334536781Z,INSERT    
2015-10-06T15:07:27.339662984Z,2015-10-06T15:07:29.345623750Z,READ
2015-10-06T15:07:31.352725607Z,2015-10-06T15:07:38.366408708Z,UPDATE

评论: 开始时间是在特定查询(插入/读取、更新)开始时给出的时间戳,因此结束时间是查询的完成时间。

谢谢。

【问题讨论】:

  • 查看this answer 和python 文档:datetime
  • 我刚刚阅读了有关 csv 的 python 解析器的信息。我完全是 python 新手,只能从我的 csv 文件中读取。

标签: python csv


【解决方案1】:

从您的示例中可以看出,您可以(大概)保证“操作”列中某种类型的第一个条目以及该相同类型的最后一个条目是开始时间和停止时间。如果你不能保证这一点,那么它会稍微复杂一些,但是让我们假设你不能 - 更加健壮。

我们可以假设的一件事是 CSV 中表示的数据是完整的。如果您缺少特定操作的条目,我们无能为力。我们还想读取时间戳,我们可以使用 dateutil.parser 模块来完成。

所以我们可以先设置一个简短的字典来跟踪我们的值,以及一个填充字典的函数,它一次接受一行。

import dateutil.parser

ops = dict()

def update_ops(opsdict, row):

    # first get the timestamp and op name in a useable format
    timestamp = dateutil.parser.parse(row[1])
    op_name = row[2]

    ## now populate, or update the dictionary
    if op_name not in opsdict:
        # sets a new dict entry with the operation's timestamp.
        # since we don't know what the start time and end time 
        # is yet, for the moment set them both.
        opsdict[op_name] = { 'start_time': timestamp,
                            'end_time': timetstamp }
    else:
        # now evaluate the current timestamp against each start_time
        # and end_time value. Update as needed.
        if opsdict[op_name]['start_time'] > timestamp:
            opsdict[op_name]['start_time'] = timestamp
        if opsdict[op_name]['end_time'] < timestamp:
            opsdict[op_name]['end_time'] = timestamp

现在我们有了一个排序函数,运行 CSV 文件阅读器并填充 ops。完成后,我们可以使用字典中的内容生成一个新的 CSV 文件。

import csv

cr = csv.reader(open('/path/to/your/file.csv'))
cr_head = cr.next()    # throw away the first row

for row in cr:
    update_ops(ops, row)

# Now write a new csv file – csv.writer is your friend :)
with open('new_operation_times.csv', 'w') as newcsv:
    cw = csv.writer(newcsv)

    # first write your header. csv.writer accepts lists for each row.
    header = 'start_time,end_time,operation'.split(',')
    cw.writerow(header)

    # now write out your dict values. You may want them sorted, 
    # but how to do that has been answered elsewhere on SE.
    for opname, timesdict in ops.items():
        row = [ opname, timesdict['start_time'], timesdict['end_time'] ]
        cw.writerow(row)

你就完成了!我试图尽可能详细地说明这一点,以便清楚发生了什么。您可能可以将其中的大部分内容分解为更少、更聪明的步骤(例如从一个 csv 读取并直接写出)。但是,如果您遵循 KISS 原则,您以后会更轻松地阅读本文并再次从中学习。

【讨论】:

  • @Araz 它们应该都在同一个文件中。传统上(这是一种很好的做法),您应该将两个 import 行放在一起,在顶部。 'ops' 在上半部分定义,ops = dict()。它在下部被调用,for row in cr: update_ops(ops, row)
  • 哦,我真傻。你明白错误告诉你什么吗?如果您想学习 Python,请遵循 Traceback。第一个错误是它起源于脚本的位置(以及 your 脚本中的行号);最后一个错误是告诉您dateutil.parser 模块的方法parse() 正在阻塞其输入。
  • 我犯了一个错误,你看:csv.reader() 对象只是一个迭代器,它逐行遍历文件,从 csv 的 第一行 开始文件你喂它,并从那里传回每一行的列表。 update_ops 函数对行中的第二个项目运行 dateutil.parser.parse() 方法,这应该是一个时间戳。但是文件的 第一行 不像 Cassandra,2015-10-06T15:07:22.333662984Z,INSERT - 它是 name,time,Operations
  • 所以在你的脚本中添加一个额外的行来扔掉第一行。由于 csv.reader() 只是一个迭代器,因此只要实例化对象,只需插入一行 cr_head = cr.next() 即可 - 这应该可以工作。 (我会编辑)
  • 另一个错误——常见;我应该循环通过 ops.items() 而不是单独的 ops。
猜你喜欢
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-13
  • 2011-12-23
  • 1970-01-01
  • 2019-04-24
相关资源
最近更新 更多