2013-11-19 2 views
5

У меня есть CSV-файл, который выглядит следующим образом:Читайте конкретные столбцы в формате CSV с помощью питона

+-----+-----+-----+-----+-----+-----+-----+-----+ 
| AAA | bbb | ccc | DDD | eee | FFF | GGG | hhh | 
+-----+-----+-----+-----+-----+-----+-----+-----+ 
| 1 | 2 | 3 | 4 | 50 | 3 | 20 | 4 | 
| 2 | 1 | 3 | 5 | 24 | 2 | 23 | 5 | 
| 4 | 1 | 3 | 6 | 34 | 1 | 22 | 5 | 
| 2 | 1 | 3 | 5 | 24 | 2 | 23 | 5 | 
| 2 | 1 | 3 | 5 | 24 | 2 | 23 | 5 | 
+-----+-----+-----+-----+-----+-----+-----+-----+

...

Как я могу читать только столбцы "AAA, DDD, FFF, GGG" в python и пропустить заголовки? Выход, который я хочу, представляет собой список кортежей, который выглядит так: [(1,4,3,20), (2,5,2,23), (4,6,1,22)]. Я собираюсь позже записать эти данные в базу данных SQL.

Я сослался на это сообщение: Read specific columns from a csv file with csv module?. Но я не думаю, что это полезно в моем случае. Поскольку мой .csv довольно большой с целым рядом столбцов, я надеюсь, что могу сказать python имена столбцов, которые я хочу, поэтому python может читать определенные столбцы по ряду строк для меня.

+1

Если вы можете использовать другую библиотеку, [Панды] (Http: //pandas.pydata .org/pandas-docs/stable/io.html) может вам помочь. –

+0

Я думаю, используя split (','), чтобы получить список заголовков и получить индекс столбца, который я хочу, а затем прочитать файл csv ... Но мне интересно, есть ли лучшие способы сделать это. –

ответ

5
def read_csv(file, columns, type_name="Row"): 
    try: 
    row_type = namedtuple(type_name, columns) 
    except ValueError: 
    row_type = tuple 
    rows = iter(csv.reader(file)) 
    header = rows.next() 
    mapping = [header.index(x) for x in columns] 
    for row in rows: 
    row = row_type(*[row[i] for i in mapping]) 
    yield row 

Пример:

>>> import csv 
>>> from collections import namedtuple 
>>> from StringIO import StringIO 
>>> def read_csv(file, columns, type_name="Row"): 
... try: 
...  row_type = namedtuple(type_name, columns) 
... except ValueError: 
...  row_type = tuple 
... rows = iter(csv.reader(file)) 
... header = rows.next() 
... mapping = [header.index(x) for x in columns] 
... for row in rows: 
...  row = row_type(*[row[i] for i in mapping]) 
...  yield row 
... 
>>> testdata = """\ 
... AAA,bbb,ccc,DDD,eee,FFF,GGG,hhh 
... 1,2,3,4,50,3,20,4 
... 2,1,3,5,24,2,23,5 
... 4,1,3,6,34,1,22,5 
... 2,1,3,5,24,2,23,5 
... 2,1,3,5,24,2,23,5 
... """ 
>>> testfile = StringIO(testdata) 
>>> for row in read_csv(testfile, "AAA GGG DDD".split()): 
... print row 
... 
Row(AAA='1', GGG='20', DDD='4') 
Row(AAA='2', GGG='23', DDD='5') 
Row(AAA='4', GGG='22', DDD='6') 
Row(AAA='2', GGG='23', DDD='5') 
Row(AAA='2', GGG='23', DDD='5') 
+0

Мне очень нравится ваше решение. Он работает эффективно. Но что, если я хочу читать столбцы в другом порядке, скажем: «AAA, FFF, DDD, GGG»? Теперь питон читает выбранные столбцы в алфавитном порядке. –

+0

Это дает мне ошибку 'row = row_type (строка [i] для i в сопоставлении) TypeError: __new __() принимает ровно 11 аргументов (2 данных)' –

+0

Ni Yan: Уже поздно, я получил симпатичный и поскользнулся в одна из отличий интерфейса между кортежем и namedtuple. Я редактировал код и предоставлял пример интерактивного сеанса, который его использует. –

1
import csv 

DESIRED_COLUMNS = ('AAA','DDD','FFF','GGG') 

f = open("myfile.csv") 
reader = csv.reader(f) 

headers = None 
results = [] 
for row in reader: 
    if not headers: 
     headers = [] 
     for i, col in enumerate(row): 
     if col in DESIRED_COLUMNS: 
      # Store the index of the cols of interest 
      headers.append(i) 

    else: 
     results.append(tuple([row[i] for i in headers])) 

print results 
+2

Роджер 'с' лучше обрабатывает файлы. Я все еще привык к использованию этого –

0

Если ваши файлы и требования относительно просты и установить, то, как только вы знаете, нужные столбцы, я бы, вероятно, использовать раскол(), чтобы разделить каждую строку данных в списке записей столбцов:

alist = aline.split('|') 

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

Как я уже сказал, я предполагаю, что ваши требования относительно фиксированы. Чем сложнее или, скорее, они могут измениться, тем больше вероятность того, что вам стоит подобрать и использовать библиотеку, предназначенную для манипулирования данными такого типа.

0

Все остальные ответы хороши, но я думаю, что было бы лучше не загружать все данные одновременно, потому что файл csv может быть действительно огромным. Я предлагаю использовать генератор.

def read_csv(f, cols): 
    reader = csv.reader(f) 
    for row in reader: 
     if len(row) == 1: 
      columns = row[0].split() 
      yield (columns[c] for c in cols) 

который может быть использован для для цикла после

with open('path/to/test.csv', 'rb') as f: 
    for bbb, ccc in read_csv(f, [1, 2]): 
     print bbb, ccc 

Конечно вы можете улучшить эту функцию, чтобы получить имя столбца вместо индекса. Для этого просто смешайте Brad M и мой.

5

Я понимаю, что ответ был принят, но если вы действительно хотите, чтобы прочитать конкретные названных столбцов из файла CSV, вы должны использовать DictReader (если вы не используете Pandas то есть).

import csv 
from StringIO import StringIO 

columns = 'AAA,DDD,FFF,GGG'.split(',') 


testdata ='''\ 
AAA,bbb,ccc,DDD,eee,FFF,GGG,hhh 
1,2,3,4,50,3,20,4 
2,1,3,5,24,2,23,5 
4,1,3,6,34,1,22,5 
2,1,3,5,24,2,23,5 
2,1,3,5,24,2,23,5 
''' 

reader = csv.DictReader(StringIO(testdata)) 

desired_cols = (tuple(row[col] for col in columns) for row in reader) 

Выход:

>>> list(desired_cols) 
[('1', '4', '3', '20'), 
('2', '5', '2', '23'), 
('4', '6', '1', '22'), 
('2', '5', '2', '23'), 
('2', '5', '2', '23')] 
1

Контекст: Для этого типа работы, которую вы должны использовать удивительную библиотеку питон petl. Это сэкономит вам много работы и потенциального разочарования в том, что вы делаете «вручную» со стандартным модулем csv. AFAIK, единственные люди, которые до сих пор используют модуль csv, - это те, кто еще не нашел лучших инструментов для работы с табличными данными (pandas, petl и т. Д.), Что хорошо, но если вы планируете работать с большим количеством данных в ваша карьера из разных странных источников, изучение чего-то вроде petl - одна из лучших инвестиций, которую вы можете сделать.Чтобы начать работу, вы должны пройти всего 30 минут после того, как вы закончили pip install petl. Документация отличная.

Ответ: Предположим, у вас есть первая таблица в csv-файле (вы также можете загрузить непосредственно из базы данных с помощью petl). Затем вы просто загрузите его и выполните следующее.

from petl import fromcsv, look, cut, tocsv  

    #Load the table 
    table1 = fromcsv('table1.csv') 
    # Alter the colums 
    table2 = cut(table1, 'Song_Name','Artist_ID') 
    #have a quick look to make sure things are ok. Prints a nicely formatted table to your console 
    print look(table2) 
    # Save to new file 
    tocsv(table2, 'new.csv') 
0

Я думаю, это поможет.

CSV

1997,Ford,E350,"ac, abs, moon",3000.00 
1999,Chevy,"Venture ""Extended Edition""","",4900.00 
1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00 

код

import csv 

def get_csv(file_name, names=None, usecols=None, mode='r', encoding="utf8", 
      quoting=csv.QUOTE_ALL, 
      delimiter=',', 
      as_obj=False): 

    class RowObject: 
     def __init__(self, **entries): 
      self.__dict__.update(entries) 

    with open(file_name, mode=mode, encoding=encoding) as csvfile: 
     data_reader = csv.reader(csvfile, quoting=quoting, delimiter=delimiter) 
     for row in data_reader: 
      if usecols and names: 
       q = dict(zip(names, (row[i] for i in usecols))) 
       yield q if not as_obj else RowObject(**q) 
      elif usecols and not names: 
       yield list(row[i] for i in usecols) 
      elif names and not usecols: 
       q = dict(zip(names, (row[k] for k, i in enumerate(row)))) 
       yield q if not as_obj else RowObject(**q) 
      else: 
       yield row 

Пример

filename = "/csv_exe/csv.csv" 
vs = get_csv(filename, names=('f1', 'f2', 'f3', 'f4', 'f5')) 
for item in vs: 
    print(item) 

результат

{'f1': '1997', 'f4': 'ac, abs, moon', 'f3': 'E350', 'f2': 'Ford', 'f5': '3000.00'} 
{'f1': '1999', 'f4': '', 'f3': 'Venture "Extended Edition"', 'f2': 'Chevy', 'f5': '4900.00'} 
{'f1': '1996', 'f4': 'MUST SELL! air, moon roof, loaded', 'f3': 'Grand Cherokee', 'f2': 'Jeep', 'f5': '4799.00'} 

example2

vs = get_csv(filename, names=('f1', 'f2'), usecols=(0, 4)) 

result2

{'f1': '1997', 'f2': '3000.00'} 
{'f1': '1999', 'f2': '4900.00'} 
{'f1': '1996', 'f2': '4799.00'} 

example3

vs = get_csv(filename, names=('f1', 'f2'), usecols=(0, 2), as_obj=True) 

result3

<__main__.get_csv.<locals>.RowObject object at 0x01408ED0> 
<__main__.get_csv.<locals>.RowObject object at 0x01408E90> 
<__main__.get_csv.<locals>.RowObject object at 0x01408F10> 

for item in vs: 
    print(item.f2) 

E350 
Venture "Extended Edition" 
Grand Cheroke 
Смежные вопросы