使用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
关键字。例如:
要遍历列表或字典的内容,您可以简单地使用 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 中处理它,而不是 print
ing 行。
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文件(稍后制作决策树)[关闭]的主要内容,如果未能解决你的问题,请参考以下文章