【问题标题】:Convert CSV table into custom format将 CSV 表格转换为自定义格式
【发布时间】:2012-06-08 03:41:12
【问题描述】:

我有一个 CSV 文件,我想将其转换为其他格式。 CSV格式如下:

A_to_B,B_to_C,C_to_D,...
0,2,1,...

即,每个标题由两个变量组成,例如A 和 B,文件中的每一行都包含一个值,即 0、1 或 2。我正在尝试编写一个 Python 脚本,该脚本将读取此 CSV 文件并将其转换为如下格式:

A,B,0
B,C,2
C,D,1
...

换句话说,它将包含标题的第一行拆分为变量(例如,A、B、C、D 等),然后匹配新格式的相应值。有谁知道如何做到这一点?我掌握了一些基础知识,但我无法正确理解实际的算法。感谢您的帮助。

更新 #1

这里有一些代码,但我没有得到正确的输出:

import csv,sys

reader = csv.reader(open(sys.argv[1], 'rt'), delimiter=',')
headers = reader.next()

data = []

for row in reader:
    line = ','.join(row)
    data.append(line)

for row in data:
    for cols, val in zip(headers, row):
        newRow = cols[0], cols[-1], val
        print newRow

CSV 文件如下所示:

A,B,C
0,2,1
0,1,1

但是,代码的输出看起来像这样,所以我需要一种以正确方式迭代 CSV 文件的方法:

('A', 'A', '0')
('B', 'B', ',')
('C', 'C', '2')
('A', 'A', '0')
('B', 'B', ',')
('C', 'C', '1')

更新 #2

如果有人偶然发现了这一点,这是我最终得到的代码(没有错误处理或任何东西,但它有效):

#!/usr/bin/python
# -*- coding: utf-8 -*-

import csv,os,sys

reader = csv.reader(open(sys.argv[1], 'rt'), delimiter=',')
headers = reader.next()
i = 1

for row in reader:
    os.system('rm id' + str(i) + '.csv')
    os.system('cat ./seeds >> id' + str(i) + '.csv')
    for srcdest,dist in zip(headers, row):
        sd = srcdest.split('_to_')
        src,dest = sd[0],sd[-1]
        if dist == '0':
            pass
        else:
            f = open('id' + str(i) + '.csv', 'a')
            f.write('{},{},{}\n'.format(src.lower().replace('_',''),dest.lower().replace('_',''),float(dist)))
    i=i+1

f.close()

感谢大家的帮助!

【问题讨论】:

  • 您可以编辑帖子的格式吗?看起来你想要不同行的东西,但你的每个数据示例都显示为一行。这让你很难理解你想要什么输出格式。
  • 已修复。谢谢你把它捡起来。 @BrenBarn

标签: python csv


【解决方案1】:

读入数据以便

row1 = ['A_to_B','B_to_C',...]
row2 = [0,2,1,...]

这可以通过简单地打开文件、读取该行并用逗号分隔来完成。您可能还想使用标准库中的csv 模块。一旦你有了,你可以做类似的事情:

for srcdest,dist in zip(row1,row2):
    sd = srcdest.split('_')
    src,dest = sd[0],sd[-1]
    f.write('{},{},{}\n'.format(src,dest,dist))

其中f 是目标文件。您也可以使用csv 模块来写入行,但仅写入文件可能更容易。

【讨论】:

    【解决方案2】:
    from itertools import izip
    
    with open("myfile.csv") as inf, open("new.csv","w") as outf:
        header = [s.split('_to_') for s in inf.next().split(',')]
        for row in inf:
            nums = (int(s) for s in row.split(','))
            for (_from, _to), num in izip(header, nums):
                outf.write("{},{},{}\n".format(_from, _to, _num))
    

    【讨论】:

      【解决方案3】:

      这是一种可能性:

      >>> header
      [u'A_to_B', u'B_to_C', u'C_to_D']
      >>> data
      [[0, 1, 2], [0, 2, 1], [1, 2, 3]]
      >>> for row in data:
      ...     for cols, val in zip(header, row):
      ...         newRow = cols[0], cols[-1], val
      ...         print newRow
      (u'A', u'B', 0)
      (u'B', u'C', 1)
      (u'C', u'D', 2)
      (u'A', u'B', 0)
      (u'B', u'C', 2)
      (u'C', u'D', 1)
      (u'A', u'B', 1)
      (u'B', u'C', 2)
      (u'C', u'D', 3)
      

      如图所示,这假设您有一个包含列名列表的“标题”事物,以及一个包含行列表的“数据”事物。 (如果你使用标准库中的 csv 模块,这基本上是你得到的。)它输出一个新的行列表。

      在此示例中,我假设所有列名都只是一个字母,因此我可以将它们作为“A_to_B”样式列名的第一个和最后一个字符来访问。如果您的列名长度不同,您可以使用 cols.split('_') 在分隔符上拆分并提取两个列名。但这只是一个与您的主要问题相切的字符串解析问题。

      编辑以响应您的编辑:

      删除您的第一个 for 循环。来自 csv.reader 的数据已经是你想要的格式;通过执行','.join',您正在将其重新打包成您不想要的格式。您的第二个 for 循环应该直接遍历阅读器:

      >>> for row in reader:
      ...     for cols, val in zip(headers, row):
      ...         newRow = cols[0], cols[-1], val
      ...         print newRow
      

      另一个问题是您在编辑中发布的数据与原始格式不同。您最初说列的形式为“A_to_B”、“B_to_C”等,但在第二个示例中,列只是“A”、“B”、“C”等。您需要解释您是如何打算从原始列名派生新的列名。

      【讨论】:

      • 如何将“数据”事物创建到这样的列表中?每当我读取 CSV 文件时,我都会得到如下所示的输出:['0', '2', '1']。相反,我想像您的示例一样将每一行视为列表中的单个项目。 @BrenBarn
      • 查看 csv 模块的文档:docs.python.org/library/csv.html。该模块允许您遍历输入文件的行。
      • 我添加了一些代码和输出,但我又卡住了。 @BrenBarn
      猜你喜欢
      • 1970-01-01
      • 2013-11-07
      • 2011-02-07
      • 1970-01-01
      • 2019-05-08
      • 2015-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多