最智能的方式将一些数据读入Python

时间:2015-04-21 13:12:29

标签: python

以下链接包含美国联邦储备银行发布的一些数据: http://www.federalreserve.gov/monetarypolicy/fomcprojtabl20150318.htm

我将该链接上的最后一个表复制并粘贴到LibreOffice Calc中的电子表格中(为了清楚起见,该表称为“适当的政策紧缩速度:目标范围的中点或联邦基金利率的目标水平”)

现在,我想要做的就是将该表读入numpy数组或python列表或其他内容,并能够对该表执行一些基本的描述性统计。请注意,该表有“空位”,其中很多都是。

这是我将电子表格保存为fomc.csv之后运行的内容:

data = []
f = open('fomc.csv', 'rt')
reader = csv.reader(f)
for row in reader:
    data.append(row)
data

我得到奇怪的东西(很多'\ xc2 \ xa0'):

 [['Midpoint of target range\nor target level (Percent)',
  '2015',
  '2016',
  '2017',
  'Longer Run'],
 ['0.125', '2', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['0.25', '', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['0.375', '1', '1', '\xc2\xa0', '\xc2\xa0'],
 ['0.5', '', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['0.625', '7', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['0.75', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['0.875', '3', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['1', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['1.125', '1', '1', '\xc2\xa0', '\xc2\xa0'],
 ['1.25', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['1.375', '2', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['1.5', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['1.625', '1', '6', '\xc2\xa0', '\xc2\xa0'],
 ['1.75', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['1.875', '\xc2\xa0', '3', '\xc2\xa0', '\xc2\xa0'],
 ['2', '\xc2\xa0', '\xc2\xa0', '1', '\xc2\xa0'],
 ['2.125', '\xc2\xa0', '1', '\xc2\xa0', '\xc2\xa0'],
 ['2.25', '\xc2\xa0', '1', '\xc2\xa0', '\xc2\xa0'],
 ['2.375', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['2.5', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['2.625', '\xc2\xa0', '1', '3', '\xc2\xa0'],
 ['2.75', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['2.875', '\xc2\xa0', '\xc2\xa0', '2', '\xc2\xa0'],
 ['3', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '1'],
 ['3.125', '\xc2\xa0', '\xc2\xa0', '4', '\xc2\xa0'],
 ['3.25', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['3.375', '\xc2\xa0', '2', '1', '\xc2\xa0'],
 ['3.5', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '7'],
 ['3.625', '\xc2\xa0', '\xc2\xa0', '2', '\xc2\xa0'],
 ['3.75', '\xc2\xa0', '1', '2', '6'],
 ['3.875', '\xc2\xa0', '\xc2\xa0', '1', '\xc2\xa0'],
 ['4', '\xc2\xa0', '\xc2\xa0', '1', '2'],
 ['4.125', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0'],
 ['4.25', '\xc2\xa0', '\xc2\xa0', '\xc2\xa0', '1']]

所以,问题:

a)获取所有这些'\ xc2 \ xa0'字符串是否正常?

b)我应该用其他值替换它们,例如''或'0',使用(即,这是一种聪明的方法吗?):

data = np.array([[el.replace('\xc2\xa0',' ') for el in row] for row in data])

c)将应该是浮点值但是字符串的数据转换为浮点值的最佳方法是什么?我需要遍历np.array吗?

考虑到第一栏,我希望能够做到像

这样的事情
data.T[0][1:] = [float(el) for el in data.T[0][1:]] 

但这不起作用,因为你不能以这种方式改变数组的切片。

2 个答案:

答案 0 :(得分:2)

a)如果您没有使用相同的编码来读取文件,那么获取错误字符是正常的。文件只是字节,它们可以根据编码进行不同的解释。 "古怪"符号几乎总是意味着你使用了错误的解释"。

b)打开文本文件时,应始终指定其编码。 Python3强迫你这样做。在Python2中你可以这样做:

from io import open

with open('fomc.csv', 'r', encoding='utf-8') as f:
    reader = csv.reader(f)

我尝试了你的例子并且无法重现同样的错误。我的列表中包含空单元格的空字符串。因为你必须用合理的默认值(例如0)替换它们,无论如何都可以。

c)您应该从csv complete中清理您的输入,然后将其传递给numpy。

你总是可以为它编写一个函数:

def sanitize_cell_content(cell_content):
    try:
        return float(cell_content)
    except ValueError:
        return 0.0

sanitized_data = [[sanitize_cell_content(el) for el in row] for row in data]

更正:正如nhawke指出的那样,假设csv在两个Python版本中都处理unicode,我犯了一个错误。在Python2中不是这种情况。即使你正确地阅读了文件,它也会爆炸。

然而,好消息是csv不是一种非常复杂的格式,所以你通常不需要csv.reader来使用它。使用unicode字符读取csv文件并将其转换为行列表就像

一样简单
with open('fomc.csv', 'r', encoding='utf-8') as f:
    data = [line.split(',') for line in f.readlines()]

从那里你可以消毒细胞并按上图所示继续进行。

答案 1 :(得分:2)

a)是的,这是正常的。您正在将UTF8编码的HTML内容粘贴到Calc中。该内容包括一个UTF8编码的NO-BREAK SPACE unicode字符,用于表格的空列。

>>> s = '\xc2\xa0'    # UTF8 encoded string
>>> s.decode('utf8')
u'\xa0'
>>> import unicodedata
>>> print unicodedata.name(s.decode('utf8'))    # decode to unicode and lookup name
NO-BREAK SPACE

看起来你使用"普通"将表粘贴到Calc中。糊。如果您使用" Paste Special"将数据粘贴到Calc中。并选择为"无格式文本"你最终会得到ASCII空格而不是非空格。此外,保存文件时,您可以指定要使用的编码。选择UTF8或ASCII,因为该表中没有任何Unicode字符,因此两者都是相同的。

b)如果您决定将未格式化的文本粘贴到Calc中,那么您可以像这样处理文件:

import csv

with open('fomc.csv') as infile:
    data= []
    for row in csv.reader(infile):
        data.append([float(field.strip()) if field.strip() else None for field in row])

data将包含:

[[0.125, 2.0, None, None, None], [0.25, None, None, None, None], ..., [4.25, None, None, None, 1.0]]

我已使用None来表示空列。您可以使用0或''如你所愿。另外,我没有复制&将列标题粘贴到CSV文件中,因此我不必担心它们。

c)参见b) - 在读取文件时对所有非空字符串执行了浮点转换。