我想读取一个arff文件,并将属性和数据分成不同的列表。该文件在这里。我尝试了以下代码
from itertools import dropwhile
attributes = []
with open('balloons.arff', 'r') as f:
for l in f.readlines(): ##1
items = l.split(' ') ##2
if items[0] == '@attribute': ##3
attributes.append(items[1]) ##4
data = dropwhile(lambda _line: "@data" not in _line, f) ##5
next(data,"") ##6
for line in data: ##7
print(line.strip()) ##8
print(attributes) ##9
当我运行此代码时,我仅获得属性列表,但是当我注释行号## 1至## 4(第一个for循环)时,程序正确地给出了数据部分。我的文件非常大,有效的解决方案将不胜感激。
解决方案
无需重新发明轮子。其他人已经为Python编写了一个ARFF解析器liac-arff。用安装pip:
pip install liac-arff
然后导入并使用该模块:
import arff
with open('balloons-adult-stretch.arff', 'rb') as handle:
data = arff.load(handle)
print(data['attributes'])
print(data['data'])
输出:
[(u'V1', [u'PURPLE', u'YELLOW']), (u'V2', [u'LARGE', u'SMALL']), (u'V3', [u'DIP', u'STRETCH']), (u'V4', [u'ADULT', u'CHILD']), (u'Class', [u'1', u'2'])]
[[u'YELLOW', u'SMALL', u'STRETCH', u'ADULT', u'2'], [u'YELLOW', u'SMALL', u'STRETCH', u'CHILD', u'2'], [u'YELLOW', u'SMALL', u'DIP', u'ADULT', u'2'], [u'YELLOW', u'SMALL', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'SMALL', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'LARGE', u'STRETCH', u'ADULT', u'2'], [u'YELLOW', u'LARGE', u'STRETCH', u'CHILD', u'2'], [u'YELLOW', u'LARGE', u'DIP', u'ADULT', u'2'], [u'YELLOW', u'LARGE', u'DIP', u'CHILD', u'1'], [u'YELLOW', u'LARGE', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'SMALL', u'STRETCH', u'ADULT', u'2'], [u'PURPLE', u'SMALL', u'STRETCH', u'CHILD', u'2'], [u'PURPLE', u'SMALL', u'DIP', u'ADULT', u'2'], [u'PURPLE', u'SMALL', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'SMALL', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'LARGE', u'STRETCH', u'ADULT', u'2'], [u'PURPLE', u'LARGE', u'STRETCH', u'CHILD', u'2'], [u'PURPLE', u'LARGE', u'DIP', u'ADULT', u'2'], [u'PURPLE', u'LARGE', u'DIP', u'CHILD', u'1'], [u'PURPLE', u'LARGE', u'DIP', u'CHILD', u'1']]
如果您确实想自己编写此代码,则代码的问题在于,您的第一个循环将从文件中读取所有行。您要么必须f.seek(0)在循环结束后将文件句柄倒回开头,要么通过实现一个简单的状态机来一次性解析它:
attributes = {}
data = []
reading_data = False
with open('balloons-adult-stretch.arff', 'r') as handle:
for line in handle:
line = line.strip()
# Ignore comments and whitespace
if line.startswith('%%') or not line:
continue
# If we have already reached the @data section, we just read indefinitely
# If @data doesn't come last, this will not work
if reading_data:
data.append(line)
continue
# Otherwise, try parsing the file
if line.startswith('@attribute'):
key, value = line.split(' ', 2)[1:]
attributes[key] = value
elif line.startswith('@data'):
reading_data = True
else:
#raise ValueError('Cannot parse line {!r}'.format(line))
pass