将CSV表转换为自定义格式

时间:2012-06-04 00:08:45

标签: python csv

我有一个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()

感谢大家的帮助!

3 个答案:

答案 0 :(得分:0)

这是一种可能性:

>>> 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”等。你需要解释一下你是怎么做的打算从原始列名中派生新的列名。

答案 1 :(得分:0)

读入数据以便

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 :(得分:0)

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))