Эффективно чтение в 2-й столбец CSV в список списков в Python 3


Я создал функцию для чтения в произвольном количестве .CSV файлов, их 2-й колонке только, в список списков (или если есть более эффективные структуры данных, то). Я хочу чтобы она была эффективной и масштабируемой/настраиваемый. Есть ли что-нибудь в нем, что может быть изменен и улучшен?

import os
FILE_NAMES=["DOCS/1.csv","DOCS/2.csv"]

def FUNC_READ_FILES(file_names): 
    nr_files=len(file_names)
    filedata=[[] for x in range(nr_files)] # efficient list of lists

    for i in range(nr_files):   # read in the files
        if(os.path.isfile(file_names[i])):
           with open(file_names[i],'r') as f:
              filedata[i]=f.readlines()
        else:
             print("ERROR: FILES ARE MISSING!!!!") 
             exit() 

    for i in range(nr_files):  # iterate through the files and only keep the 2nd column, remove \n if it's end of line
       for k in range(len(filedata[0])):
        filedata[i][k]=filedata[i][k].strip().split(',')[1]

    return (filedata)

FUNC_READ_FILES(FILE_NAMES)


Комментарии
2 ответа

Поскольку вы находитесь в Python 3.X, я хотел бы предложить, глядя в ввода-вывода для интенсивного файл процессора, операции ввода-вывода.


В ваш код, вы сначала читать каждую строку из CSV в память, а затем обрабатывать эти данные. Это очень неэффективно. Процесс этих линий, как только вы добраться до них, так что ваши затраты памяти минимальны.


Вместо перебора индексов списка файлов, перебирайте сами файлы:

filedata = []
for file_name in file_names:
if(os.path.isfile(file_name)):
with open(file_name, 'r') as f:
reader = csv.reader(f)
filedata.append([row[1] for row in reader])
else:
print("ERROR: FILES ARE MISSING!!!!")
exit()

будет заменить следующим

for i in range(nr_files):   # read in the files
if(os.path.isfile(file_names[i])):
with open(file_names[i],'r') as f:
filedata[i]=f.readlines()
else:
print("ERROR: FILES ARE MISSING!!!!")
exit()
for i in range(nr_files): # iterate through the files and only keep the 2nd column, remove \n if it's end of line
for k in range(len(filedata[0])):
filedata[i][k]=filedata[i][k].strip().split(',')[1]

0
ответ дан 8 апреля 2018 в 05:04 Источник Поделиться

Общие замечания

оптосоз 8

для наименования и кода, стараюсь следовать Пеп-8


  • lower_case для переменные и имена функций

  • пробелы вокруг операторов

главного охранника

поставить вызов функции после if __name__ == '__main__':, Так что вы можете загрузить скрипт из какого-то другого без его выполнения кода сразу

зацикливание

Не цикл по индексам. Код for i in range(nr_files): это намного чище, используя enumerate: for i, filename in enumerate(file_names).

Я предлагаю вам ознакомиться с отличным зацикливание, как профи говорят Дэвид Баумголд

функции

Вместо того, что функции 1, чтобы загрузить файлы, перебрать их и выбрать правильный элемент, seasiest бы разделить, если в разных функциях:


  1. принимает список файлов и передает их по одному на разбор

  2. парсить один файл

Генераторы

Наиболее подходящие для Python эффективным способом для этого будет использование генераторов, pathlib.Path и встроенный csv модуль

Мое решение

парсить один файл

Эта функция принимает файловый дескриптор, и анализирует требуемый элемент из строки

import csv
from pathlib import Path

def parse_file(filehandle, field_name):
kwargs = { # https://docs.python.org/3/library/csv.html#csv-fmt-params
'delimiter': ',',
'skipinitialspace': True,
# ...
}
# field_name = b # or the column name
reader = csv.DictReader(filehandle, **kwargs) # or csv.reader if there is no header, and it might be faster
for line in reader:
yield line[field_name]

Это можно легко проверить как это:

from io import StringIO
csv_str = '''a, b, c
0, 1, 2
3, 4, 5'''
with StringIO(csv_str, newline='') as file:
print(list(parse_file(file, 'b')))


['1', '4']

анализ нескольких файлов

def parse_files(files):
for file in files:
try:
with filename.open('r', newline='', ) as csv_file:
yield list(parse_file(csv_file))
except FileNotFoundError:
print("ERROR: FILES ARE MISSING!!!!")
raise

Теперь у нас есть хороший метод анализа информации, нам просто нужно вызвать ее с последующей файлов

главная

def main(files):
results = list(parse_files(files))
return results

if __name__ == '__main__':

files= [Path("DOCS/1.csv"),Path("DOCS/2.csv")]
main(files)

1
ответ дан 9 апреля 2018 в 08:04 Источник Поделиться