在 Python 中读取 scipy/numpy 中的 csv 文件

Posted

技术标签:

【中文标题】在 Python 中读取 scipy/numpy 中的 csv 文件【英文标题】:reading csv files in scipy/numpy in Python 【发布时间】:2011-02-21 00:16:08 【问题描述】:

我在 python 中读取由制表符分隔的 csv 文件时遇到问题。我使用以下功能:

def csv2array(filename, skiprows=0, delimiter='\t', raw_header=False, missing=None, with_header=True):
    """
    Parse a file name into an array. Return the array and additional header lines. By default,
    parse the header lines into dictionaries, assuming the parameters are numeric,
    using 'parse_header'.
    """
    f = open(filename, 'r')
    skipped_rows = []
    for n in range(skiprows):
        header_line = f.readline().strip()
        if raw_header:
            skipped_rows.append(header_line)
        else:
            skipped_rows.append(parse_header(header_line))
    f.close()
    if missing:
        data = genfromtxt(filename, dtype=None, names=with_header,
                          deletechars='', skiprows=skiprows, missing=missing)
    else:
    if delimiter != '\t':
        data = genfromtxt(filename, dtype=None, names=with_header, delimiter=delimiter,
                  deletechars='', skiprows=skiprows)
    else:
        data = genfromtxt(filename, dtype=None, names=with_header,
                  deletechars='', skiprows=skiprows)        
    if data.ndim == 0:
    data = array([data.item()])
    return (data, skipped_rows)

问题是 genfromtxt 抱怨我的文件,例如出现错误:

Line #27100 (got 12 columns instead of 16)

我不确定这些错误来自哪里。有任何想法吗?

这是导致问题的示例文件:

#Gene   120-1   120-3   120-4   30-1    30-3    30-4    C-1 C-2 C-5 genesymbol  genedesc
ENSMUSG00000000001  7.32    9.5 7.76    7.24    11.35   8.83    6.67    11.35   7.12    Gnai3   guanine nucleotide binding protein alpha
ENSMUSG00000000003  0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 Pbsn    probasin

有没有更好的方法来编写通用的 csv2array 函数?谢谢。

【问题讨论】:

看来,当它到达文件的第三行时,它认为有 16 列(出于某种原因基于第 2 行),然后拒绝该文件。知道为什么第 2 行的最后一个字段会这样解释吗?它没有制表符,只有空格,但它似乎将第 2 行最后一个字段中的每个单词解释为一个列字段。 您的解析器必须将空格解释为分隔符。我不确定 genfromtxt 做了什么,但如果它正在构建一个数组,如果你给它提供比以前任何其他更大的行,它可能会默默地扩展自己,但是当它变得更小时会生气。在任何情况下,如果您要处理潜在的未知数据,使用 csv 模块会更加稳健。 但是我怎样才能稳健地从 csv 转到数组? 您是否尝试将 '\t' 指定为 genfromtxt 的分隔符? 【参考方案1】:

查看 python CSV 模块:http://docs.python.org/library/csv.html

import csv
reader = csv.reader(open("myfile.csv", "rb"), 
                    delimiter='\t', quoting=csv.QUOTE_NONE)

header = []
records = []
fields = 16

if thereIsAHeader: header = reader.next()

for row, record in enumerate(reader):
    if len(record) != fields:
        print "Skipping malformed record %i, contains %i fields (%i expected)" %
            (record, len(record), fields)
    else:
        records.append(record)

# do numpy stuff.

【讨论】:

不幸的是,这不会从结果中生成一个 numpy 数组 你可以对循环体中的数据做任何你喜欢的事情;这是一个由分隔符分解的列表。您可以检查它是否与您期望的一样长(在编辑的示例中),或者对每个字段进行验证以确保您没有将垃圾传递到您的 numpy 数组中。【参考方案2】:

请问您为什么不使用内置的 csv 阅读器? http://docs.python.org/library/csv.html

我已经非常有效地使用了 numpy/scipy。我会分享我的代码,但不幸的是它归我的雇主所有,但编写自己的代码应该非常简单。

【讨论】:

【参考方案3】:

我已经成功地使用了两种方法; (1):如果我只是需要读取任意 CSV,我使用了 CSV 模块(正如其他用户所指出的),以及(2):如果我需要重复处理已知的 CSV(或任何)格式,我写一个简单的解析器。

看来你的问题属于第二类,解析器应该很简单:

f = open('file.txt', 'r').readlines()
for line in f:
 tokens = line.strip().split('\t')
 gene = tokens[0]
 vals = [float(k) for k in tokens[1:10]]
 stuff = tokens[10:]
 # do something with gene, vals, and stuff

您可以在阅读器中添加一行以跳过 cmets(`if tokens[0] == '#': continue')或处理空行('if tokens == []: continue')。你明白了。

【讨论】:

【参考方案4】:

我认为 Nick T 的方法会是更好的方法。我会做一个改变。因为我将替换以下代码:

for row, record in enumerate(reader):
if len(record) != fields:
    print "Skipping malformed record %i, contains %i fields (%i expected)" %
        (record, len(record), fields)
else:
    records.append(record)

records = np.asrray([row for row in reader if len(row) = fields ])
print('Number of skipped records: %i'%(len(reader)-len(records)) #note you have to do more than len(reader) as an iterator does not have a length like a list or tuple

列表推导将返回一个 numpy 数组并利用预编译的库,这将大大加快速度。另外,我建议使用 print() 作为函数而不是 print "",因为前者是 python3 的标准,这很可能是未来的标准,我会使用 logging 而不是 print。

【讨论】:

【参考方案5】:

它可能来自数据文件中的第 27100 行...它有 12 列而不是 16 列。即它有:

separator,1,2,3,4,5,6,7,8,9,10,11,12,separator

它期待这样的事情:

separator,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,separator

我不确定你想如何转换你的数据,但如果你有不规则的行长度,最简单的方法是这样的:

lines = f.read().split('someseparator')
for line in lines:
    splitline = line.split(',')
    #do something with splitline

【讨论】:

我添加了一个导致错误的示例文件——在我看来它的列数是正确的,但由于某种原因它认为它有 16 列。知道是什么原因造成的吗?

以上是关于在 Python 中读取 scipy/numpy 中的 csv 文件的主要内容,如果未能解决你的问题,请参考以下文章

Python 中的二阶导数 - scipy/numpy/pandas

Python scipy/numpy中相关性的层次聚类?

通过Scipy和Numpy使用Python将数据拟合到ODE系统

是否有关于 scipy、numpy、pandas、scikit 生态系统中包之间相互依赖关系的文档? Python

Ubuntu-Python2.7安装 scipy,numpy,matplotlib 和pip

在 Python / NumPy 中计算矩阵的 Jordan 范式