使用python解析CSV文件(稍后制作决策树)

时间:2010-04-28 00:53:18

标签: python csv decision-tree

首先,完全披露:这是单向分配,所以我不想接收代码。 :)。我更需要寻找方法;我已经非常是python的新手,读过一本书但还没有编写任何代码。

整个任务是导入CSV文件的内容,从CSV文件的内容创建决策树(使用ID3 algorithm),然后解析第二个CSV文件以对树运行。有一个很大的(可理解的)偏好,它能够处理不同的CSV文件(我问我们是否允许对列名进行硬编码,主要是为了消除它的可能性,答案是否定的)。

CSV文件采用相当标准的格式;标题行标有#,然后显示列名,之后的每一行都是一系列简单的值。例如:

# Column1, Column2, Column3, Column4
Value01, Value02, Value03, Value04
Value11, Value12, Value13, Value14

目前,我正在努力解决第一部分:解析CSV。为了做出决策树的决策,字典结构似乎是最合乎逻辑的;所以我想在这些方面做点什么:

Read in each line, character by character
If the character is not a comma or a space
    Append character to temporary string
If the character is a comma
    Append the temporary string to a list
    Empty string
Once a line has been read
    Create a dictionary using the header row as the key (somehow!)
    Append that dictionary to a list

但是,如果我这样做,我不确定如何在键和值之间进行映射。我也想知道是否有某种方法可以对列表中的每个字典执行操作,因为我需要做的事情是“每个人都返回列Column1和Column4的值,所以我可以数谁有什么!“ - 我认为有一些机制,但我认为我不知道该怎么做。

字典是最好的方法吗?使用其他数据结构做事情会更好吗?如果是这样,是什么?

7 个答案:

答案 0 :(得分:4)

Python内置了一些非常强大的语言结构。您可以从以下文件中读取行:

with open(name_of_file,"r") as file:
    for line in file:
         # process the line

您可以使用string.split函数分隔逗号中的行,您可以使用string.strip来消除插入的空格。 Python功能非常强大listsdictionaries

要创建列表,只需使用[]等空括号,而创建使用{}的空字典:

mylist = []; # Creates an empty list
mydict = {}; # Creates an empty dictionary

您可以使用.append()函数插入列表,同时可以使用索引下标插入字典。例如,您可以使用mylist.append(5)将5添加到列表中,同时可以使用mydict[key]=value将密钥key与值value相关联。要测试字典中是否存在密钥,您可以使用in关键字。例如:

if key in mydict:
   print "Present"
else:
   print "Absent"

要遍历列表或字典的内容,您只需使用for循环,如下所示:

for val in mylist:
    # do something with val

for key in mydict:
    # do something with key or with mydict[key]

因为在很多情况下,迭代列表时必须同时具有值​​和索引,所以还有一个名为enumerate的内置函数可以节省您自己计算索引的麻烦:

for idx, val in enumerate(mylist):
    # do something with val or with idx. Note that val=mylist[idx]

上面的代码功能相同:

idx=0
for val in mylist:
   # process val, idx
   idx += 1

如果您这样选择,也可以迭代索引:

for idx in xrange(len(mylist)):
    # Do something with idx and possibly mylist[idx]

此外,您可以使用len获取列表中的元素数量或字典中的键数。

可以通过使用列表理解对字典或列表的每个元素执行操作;但是,我建议您只使用for循环来完成该任务。但是,作为一个例子:

>>> list1 = range(10)
>>> list1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list2 = [2*x for x in list1]
>>> list2
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

如果您有时间,我建议您阅读Python tutorial以获得更深入的知识。

答案 1 :(得分:4)

使用docs.python.org中的csv模块的示例:

import csv
reader = csv.reader(open("some.csv", "rb"))
for row in reader:
    print row

而不是print行,您可以将每行保存到列表中,然后在ID3中处理它。

database.append(row)

答案 2 :(得分:2)

简短回答:不要浪费时间和精力(1)重新实现内置的csv模块(2)读取csv模块的源代码(用C语言编写) - 只是使用它!

答案 3 :(得分:2)

查看csv.DictReader。

示例:

import csv
reader = csvDictReader(open('my_file.csv','rb') # 'rb' = read binary
for d in reader:
    print d # this will print out a dictionary with keys equal to the first row of the file.

答案 4 :(得分:1)

查看内置CSV module。虽然你可能不能只使用它,但你可以偷看一下代码......

如果这是禁忌,你的(伪)代码看起来非常好,尽管你应该使用str.split()函数并使用它,逐行读取文件。

答案 5 :(得分:1)

正确解析CSV

我会避免使用str.split()来解析字段,因为str.split()将无法识别引用的值。许多真实的CSV文件都使用引号。 http://en.wikipedia.org/wiki/Comma-separated_values

使用引用值的示例记录:

1997,Ford,E350,"Super, luxurious truck"

如果你使用str.split(),你会得到一个包含5个字段的记录:

('1997', 'Ford', 'E350', '"Super', ' luxurious truck"')

但你真正想要的是这样的记录,有4个字段:

('1997', 'Ford', 'E350', 'Super, luxurious truck')

此外,除了数据中的逗号之外,您可能还必须处理数据中的换行符“\ r \ n”或“\ n”。例如:

1997,Ford,E350,"Super
luxurious truck"
1997,Ford,E250,"Ok? Truck"

小心使用:

file = open('filename.csv', 'r')
for line in file:
    # problem here, "line" may contain partial data

另外,就像约翰提到的那样,CSV标准是,如果你得到一个双引号,那么在报价中,它会变成一个引用。

1997,Ford,E350,"Super ""luxurious"" truck"

('1997', 'Ford', 'E350', 'Super "luxurious" truck')

所以我建议像这样修改你的有限状态机:

  • 一次解析每个角色。
  • 检查是否是引用,然后将状态设置为“引用”
  • 如果“在引号中”,则将所有字符存储在当前字段中,直到有另一个引号。
  • 如果“在引号中”,并且还有另一个引号,请将引号字符存储在字段数据中。 (不是结束,因为空白字段不应该是“数据”,“数据”而是“数据,数据”)
  • 如果不是“引用”,请存储字符,直到找到逗号或换行符。
  • 如果使用逗号,请保存字段并开始新字段。
  • 如果换行,保存字段,保存记录,开始新记录和新字段。

另一方面,有趣的是,我从未在CSV中看到使用#注释掉的标题。所以对我来说,这意味着您可能还必须在数据中查找注释行。使用#注释掉CSV文件中的一行不是标准的。

使用标题键

将找到的字段添加到记录字典中

根据内存要求,如果CSV足够小(可能是10k到100k记录),使用字典就可以了。只需存储所有列名的list,以便按索引(或数字)访问列名。然后在有限状态机中,当找到逗号时递增列索引,并在找到换行符时重置为0.

因此,如果您的标题是header = ['Column1', 'Column2']那么当您找到数据字符时,请按以下方式添加:

record[header[column_index]] += character

答案 6 :(得分:0)

我不太了解@Kaloyan Todorov谈到的内置csv模块,但是,如果你正在阅读逗号分隔的行,那么你可以很容易地做到这一点:

for line in file:
    columns = line.split(',')
    for column in columns:
        print column.strip()

这将打印每一行的所有条目,而不会引出拖尾空格。