ускорение разбора файлов - PullRequest
2 голосов
/ 05 июня 2010

следующая функция разбирает файл CSV в список словарей, где каждый элемент в списке является словарем, значения которого индексируются заголовком файла (предполагается, что это первая строка).

эта функция работает очень медленно, ~ 6 секунд для файла, который относительно мал (менее 30000 строк).

как я могу ускорить его?

def csv2dictlist_raw(filename, delimiter='\t'):
    f = open(filename)
    header_line = f.readline().strip()
    header_fields = header_line.split(delimiter)
    dictlist = []
    # convert data to list of dictionaries
    for line in f:
    values = map(tryEval, line.strip().split(delimiter))
    dictline = dict(zip(header_fields, values))
    dictlist.append(dictline)
    return (dictlist, header_fields)

в ответ на комментарии:

Я знаю, что есть модуль CSV, и я могу использовать его так:

data = csv.DictReader(my_csvfile, delimiter=delimiter)

это намного быстрее. Однако проблема заключается в том, что он не приводит к автоматическому приведению чисел, которые, очевидно, являются числами с плавающей точкой и целыми числами, а делает их строками. Как я могу это исправить?

Использование класса "Sniffer" не работает для меня. Когда я пробую это на моих файлах, я получаю сообщение об ошибке:

File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/csv.py", line 180, in sniff
    raise Error, "Could not determine delimiter"
Error: Could not determine delimiter

Как я могу заставить DictReader анализировать поля по их типам, когда это очевидно?

спасибо.

спасибо.

Ответы [ 3 ]

3 голосов
/ 05 июня 2010
import ast

# find field types
for row in csv.DictReader(my_csvfile, delimiter=delimiter):
    break
else:
    assert 0, "no rows to process"
cast = {}
for k, v in row.iteritems():
    for f in (int, float, ast.literal_eval):
        try: 
            f(v)
            cast[k] = f
            break
        except (ValueError, SyntaxError):
            pass
    else: # no suitable conversion
        cast[k] = lambda x: x.decode(encoding)

# read data
my_csvfile.seek(0)

data = [dict((k.decode(encoding), cast[k](v)) for k, v in row.iteritems())
        for row in csv.DictReader(my_csvfile, delimiter=delimiter)]
1 голос
/ 28 июля 2015

А как же панды?

import pandas as pd

# load everything in
df = pd.read_table(filename)

# coerce strings to numeric
df = df.convert_objects(convert_numeric=True)
1 голос
/ 05 июня 2010

Я вижу несколько проблем с вашим кодом:

  • Зачем вам нужны диктовки? Ключи хранятся в каждом экземпляре dict, что увеличивает потребление памяти.

  • Вам действительно нужно хранить все экземпляры в памяти или можно использовать yield?

  • Попытка преобразования каждого значения занимает время и не имеет смысла в моем варианте. Если у вас есть столбец со значениями «abc» и «123», последнее значение, вероятно, должно быть строкой. Поэтому тип столбца должен быть фиксированным, и вы должны сделать преобразование явным.

  • Даже если вы хотите использовать логику преобразования: используйте модуль csv и впоследствии конвертируйте значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...