Чтение csv файлов в scipy/numpy в Python

У меня возникли проблемы с чтением файла csv, ограниченного вкладками, в python. Я использую следующую функцию:

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? спасибо.

Ответ 1

Проверьте модуль CSV python: 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.

Ответ 2

Могу ли я спросить, почему вы не используете встроенный считыватель csv? http://docs.python.org/library/csv.html

Я использовал его очень эффективно с numpy/scipy. Я бы поделился своим кодом, но, к сожалению, он принадлежал моему работодателю, но было бы очень просто написать свой собственный.

Ответ 3

Вероятно, он появился в строке 27100 в вашем файле данных... и у него было 12 столбцов вместо 16. I.e. он имел:

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

Ответ 4

Я успешно использовал две методологии; (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

Вы можете добавить строку в читатель для пропусков комментариев (`if tokens [0] == '#': продолжить ') или обрабатывать пустые строки (' if tokens == []: continue '). Вы получаете идею.

Ответ 5

Я думаю, что подход Ника Т будет лучшим способом. Я бы сделал одно изменение. Поскольку я бы заменил следующий код:

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() как функцию по сравнению с печатью ", поскольку первая является стандартом для python3, что, скорее всего, будущее, и я бы использовал logging над печатью.