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

Posted

技术标签:

【中文标题】使用python解析CSV文件(稍后制作决策树)[关闭]【英文标题】:Parse a CSV file using python (to make a decision tree later) [closed] 【发布时间】:2011-02-13 03:31:00 【问题描述】:

首先,全面披露:这是针对 uni 分配的,所以我不想收到代码。 :)。我更在寻找方法;我非常是 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 的值,所以我可以数数谁有什么!” - 我认为有一些机制,但我认为我不知道该怎么做。

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

【问题讨论】:

【参考方案1】:

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

使用 open(name_of_file,"r") 作为文件: 对于文件中的行: # 处理该行

您可以使用string.split 函数以逗号分隔行,您可以使用string.strip 来消除中间空格。 Python有非常强大的lists和dictionaries。

要创建一个列表,您只需使用 [] 之类的空括号,而要创建一个空字典,您可以使用 :

我的列表 = []; # 创建一个空列表 mydict = ; # 创建一个空字典

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

如果在 mydict 中键入: 打印“礼物” 别的: 打印“缺席”

要遍历列表或字典的内容,您可以简单地使用 for 循环,如下所示:

对于 mylist 中的 val: # 用 val 做一些事情 对于 mydict 中的键: # 用 key 或 mydict[key] 做一些事情

由于在许多情况下,迭代列表时需要同时具有值​​和索引,因此还有一个名为 enumerate 的内置函数可以省去您自己计算索引的麻烦:

对于枚举(mylist)中的 idx、val: # 用 val 或 idx 做一些事情。注意 val=mylist[idx]

上面的代码在功能上与:

idx=0 对于 mylist 中的 val: # 进程 val, idx idx += 1

如果您愿意,也可以迭代索引:

对于 xrange(len(mylist)) 中的 idx: # 用 idx 和 mylist[idx] 做一些事情

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

可以通过使用列表推导对字典或列表的每个元素执行操作;但是,我建议您简单地使用 for 循环来完成该任务。但是,例如:

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

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

【讨论】:

【参考方案2】:

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

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

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

database.append(row)

【讨论】:

【参考方案3】:

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

【讨论】:

示例代码会有所帮助。 @blokely:阅读 OP 写的内容会有所帮助:“”“这是一个 uni 任务,所以我不想收到代码”“”【参考方案4】:

查看 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.

【讨论】:

代码示例中有两个错别字:缺少。在csvDictReader 并且没有关闭)【参考方案5】:

看看内置的CSV module。虽然你可能不能只使用它,但你可以先看看代码......

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

【讨论】:

【参考方案6】:

正确解析 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

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

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

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

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

一次解析每个字符。 检查是否是报价单,然后将状态设置为“报价单中” 如果“在引号中”,则将所有字符存储在当前字段中,直到出现另一个引号。 如果“in quote”,并且有另一个引号,则将引号字符存储在字段数据中。 (不是结尾,因为空白字段不应该是 `data,"",data` 而是 `data,,data`) 如果不是“引号”,则存储字符,直到找到逗号或换行符。 如果是逗号,则保存字段并开始一个新字段。 如果换行,保存字段,保存记录,开始一个新记录和一个新字段。

顺便说一句,有趣的是,我从未见过在 CSV 中使用 # 注释掉的标题。所以对我来说,这意味着您可能也必须在数据中查找注释行。使用 # 注释掉 CSV 文件中的一行是不标准的。

使用标题键将找到的字段添加到记录字典中

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

所以如果你的标题是header = ['Column1', 'Column2'] 那么当你找到一个数据字符时,像这样添加它:

record[header[column_index]] += character

【讨论】:

你忘了说当原始数据中有引号时会发生什么,导致像Colt,45,"owned by John ""Quick Draw"" McGraw"这样的csv输入......有限状态机变得相当复杂。 谢谢约翰,我更新了答案。 所以现在你的有限状态机似乎需要一个 1 字节的前瞻缓冲区(“下一个字符是引号”),这看起来不太好——决策过程应该只需要一个当前状态和一个输入字符。顺便说一句,当她的练习的目的似乎是编写决策树脚本而不是低级字节抨击时,你为什么要怂恿 OP 编写 FSM? CSV 模块的方法在 QUOTE_IN_QUOTED_FIELD 状态下会在 svn.python.org/projects/python/trunk/Modules/_csv.c 中执行 parse_add_char(self, c)(与我的方法相同)。只是展示了实现 CSV 解析器的所有问题。 OP 说:“目前,我正在尝试解决第一部分:解析 CSV” 如果允许 OP 使用 CSV 模块,那就太好了。尽管如果她使用 CSV 模块,标题的第一个值将不会正确显示,因为它被“注释掉”了 #。所以这向我表明,项目的那一部分正在编写解析器。 对不起,其实他们的方法是向后看。如果在报价中,并且当前是报价等...您是对的,约翰。更新了答案。【参考方案7】:

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

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

这将打印每行的所有条目,不带前导尾空格。

【讨论】:

"""我对内置 csv 模块不太了解""" ...你该弥补这个缺陷了 ;-) 完全同意。昨晚花了一个小时左右阅读文档。时间花得很好。

以上是关于使用python解析CSV文件(稍后制作决策树)[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

决策树的实现

决策树的可视化解读

如何在python中可视化决策树?

在 jupyter 中构建决策树的 KeyError:

决策树问题一:读取文件头报错问题 has no attribute next

解析决策树(来自 WEKA 分类器)以在 R 中绘图?