1

我正在使用 Python 生成一个由很长的行组成的 ASCII 文件。这是一个示例行(假设文件中的第 100 行,我添加了“[...]”以缩短该行):

{6 1,14 1,[...],264 1,270 2,274 2,[...],478 1,479 8,485 1,[...]}

如果我打开用 ipython 生成的 ASCII 文件:

f = open('myfile','r')
print repr(f.readlines()[99])

我确实获得了正确打印的预期行(我添加了“[...]”以缩短行):

'{6 1,14 1,[...],264 1,270 2,274 2,[...],478 1,479 8,485 1,[...]}\n'

相反,如果我用应该读取它的程序打开这个文件,它会产生一个异常,在 478 1 之后抱怨一个意外的对。所以我尝试用vim打开文件。vim仍然显示没有问题,但是如果我复制vim打印的行并将其粘贴到另一个文本编辑器中(在我的情况下为TextMate),这就是我获得的行('[...]' 由我添加到缩短线):

{6 1,14 1,[...],264 1,270      2,274 2,[...],478 1,4     79 8,485 1,[...]}

这条线在 478 1 之后确实有问题。我尝试以不同的方式生成我的线(连接,与 cStringIO,...),但我总是得到这个结果。例如,当使用 cStringIO 时,生成的行如下所示(即使我也尝试更改它,但没有运气):

def _construct_arff(self,attributes,header,data_rows):
  """Create the string representation of a Weka ARFF file.
     *attributes* is a dictionary with attribute_name:attribute_type
       (e.g., 'num_of_days':'NUMERIC')
     *header* is a list of the attributes sorted
       (e.g., ['age','name','num_of_days'])
     *data_rows* is a list of lists with the values, sorted as in the header
       (e.g., [ [88,'John',465],[77,'Bob',223]]"""

  arff_str = cStringIO.StringIO()
  arff_str.write('@relation %s\n' % self.relation_name)

  for idx,att_name in enumerate(header):
    try:
      name = att_name.replace("\\","\\\\").replace("'","\\'")
      arff_str.write("@attribute '%s' %s\n" % (name,attributes[att_name]))
    except UnicodeEncodeError:
      arff_str.write('@attribute unicode_err_%s %s\n' 
                     % (idx,attributes[att_name]))

  arff_str.write('@data\n')
  for data_row in data_rows:
    row = []
    for att_idx,att_name in enumerate(header):
      att_type = attributes[att_name]
      value = data_row[att_idx]
      # numeric attributes can be sparse: None and zeros are not written
      if ((not att_type == constants.ARRF_NUMERIC)
          or not ((value == None) or value == 0)):
        row.append('%s %s' % (att_idx,value))
    arff_str.write('{' + (','.join(row)) + '}\n')
  return arff_str.getvalue()

更新:从上面的代码可以看出,该函数将给定的数据集转换为特殊的 arff 文件格式。我注意到我创建的属性之一包含作为字符串的数字(例如,'1',而不是 1)。通过将这些数字强制转换为整数:

features[name] = int(value)

我成功地重新创建了 arff 文件。但是我看不出这是一个值如何影响 *att_idx* 的格式,它始终是一个整数,正如@JohnMachin 和 @gnibbler 所指出的那样(谢谢你的回答,顺便说一句) . 所以,即使我的代码现在运行,我仍然不明白为什么会发生这种情况。如果没有正确转换为int ,该值如何影响其他内容的格式?

此文件包含格式错误的版本。

4

1 回答 1

11

内置函数repr是你的朋友。它将明确地向您显示文件中的内容。

做这个:

f = open('myfile','r')
print repr(f.readlines()[99])

并编辑您的问题以显示结果。

更新:至于它是如何到达那里的,这是不可能的,因为它不可能是由您显示的代码生成的。该值37应该是来自 att_idx 的值,enumerate()因此必须是 int。您正在用 %s 格式化这个 int ... 37 不能成为3rubbish7. 这也应该按 0、1 等顺序生成 att_idx,但是您缺少许多值,并且循环内没有任何条件。

请向我们展示您实际运行的代码。

更新

再一次,这段代码不会运行:

for idx,att_name in enumerate(header):
    arff_str.write("@attribute '%s' %s\n" % (name,attributes[att_name]))

因为name没有定义;你可能的意思是att_name

也许我们可以缩短所有这些填充物:将输出文件的副本(如果它很大,则压缩)在网络上的某个地方,这样我们就可以亲眼看到可能会干扰其消费者的内容。请编辑您的问题以说明问题所在的行。

顺便说一句,您说某些数据是字符串而不是整数,如果您int通过执行强制数据来解决问题features[name] = int(value)......什么是“特征”?什么名字'??

这些字符串unicode中的任何一个都不是str吗?

更新 2(在网络上发布错误文件后)

没有提供关于哪条线路出现问题的信息。事实证明,没有任何行显示出属性 479 所描述的问题。我编写了这个检查脚本:

import re, sys
# sample data line:
# {40 1,101 3,319 2,375 2,525 2,530 bug}
# Looks like all data lines end in ",530 bug}" or ",530 other}"
pattern1 = r"\{(?:\d+ \d+,)*\d+ \w+\}$"
matcher1 = re.compile(pattern1).match
pattern2 = r"\{(?:\d+ \d+,)*"
matcher2 = re.compile(pattern2).match
bad_atts = re.compile(r"\D\d+\s+\W").findall
got_data = False
for lino, line in enumerate(open(sys.argv[1], "r"), 1):
    if not got_data:
        got_data = line.startswith('@data')
        continue
    if not matcher1(line):
        print
        print lino, repr(line)
        m = matcher2(line)
        if m:
            print "OK up to offset", m.end()
            print bad_atts(line)

示例输出(包装在第 80 列):

581 '{2 1,7 1,9 1,12 1,13 1,14 1,15 1,16 1,17 1,18 1,21 1,22 1,24 1,25 1,26 1,27
 1,29 1,32 1,33 1,36 1,39 1,40 1,44 1,48 1,49 1,50 1,54 1,57 1,58 1,60 1,67 1,68
 1,69 1,71 1,74 1,75 1,76 1,77 1,80 1,88 1,93 1,101 ,103 6,104 2,109 20,110 3,11
2 2,114 1,119 17,120 4,124 39,128 5,137 1,138 1,139 1,162 1,168 1,172 18,175 1,1
76 6,179 1,180 1,181 2,185 2,187 9,188 8,190 1,193 1,195 2,196 4,197 1,199 3,201
 3,202 4,203 5,206 1,207 2,208 1,210 2,211 1,212 5,213 1,215 2,216 3,218 2,220 2
,221 3,225 8,226 1,233 1,241 4,242 1,248 5,254 2,255 1,257 4,258 4,260 1,266 1,2
68 1,269 3,270 2,271 5,273 1,276 1,277 1,280 1,282 1,283 11,285 1,288 1,289 1,29
6 8,298 1,299 1,303 1,304 11,306 5,308 1,309 8,310 1,315 3,316 1,319 11,320 5,32
1 11,322 2,329 1,342 2,345 1,349 1,353 2,355 2,358 3,359 1,362 1,367 2,368 1,369
 1,373 2,375 9,377 1,381 4,382 1,383 3,387 1,388 5,395 2,397 2,400 1,401 7,407 2
,412 1,416 1,419 2,421 2,422 1,425 2,427 1,431 1,433 7,434 1,435 1,436 2,440 1,4
49 1,454 2,455 1,460 3,461 1,463 1,467 1,470 1,471 2,472 7,477 2,478 11,479 31,4
82 6,485 7,487 1,490 2,492 16,494 2,495 1,497 1,499 1,501 1,502 1,503 1,504 11,5
06 3,510 2,515 1,516 2,517 3,518 1,522 4,523 2,524 1,525 4,527 2,528 7,529 3,530
 bug}\n'
OK up to offset 203
[',101 ,']

709 '{101 ,124 2,184 1,188 1,333 1,492 3,500 4,530 bug}\n'
OK up to offset 1
['{101 ,']

所以看起来属性att_idx == 101有时可以包含空字符串''。您需要理清如何处理此属性。如果你解开这个拜占庭代码,它会帮助你思考:

  if ((not att_type == constants.ARRF_NUMERIC)
      or not ((value == None) or value == 0)):

旁白:“脏话删除”的代码不会运行;它应该是 ARFF,而不是 ARRF

进入:

if value or att_type != constants.ARFF_NUMERIC:

或者也许只是if value:过滤掉所有None,0"". 请注意,这att_idx == 101对应于在 ARFF 文件头中赋予 STRING 类型的属性“priority”:

[line 103] @attribute 'priority' STRING

顺便说一句,您关于features[name] = int(value)“解决”问题的说法非常可疑;int("")引发异常。

它可以帮助您阅读本 wiki 部分末尾关于稀疏 ARFF 文件的警告。

于 2012-04-21T08:41:15.847 回答