извлечение строк и имен файлов из нескольких CSV-файлов

#python

#python

Вопрос:

У меня есть несколько CSV-файлов с датой в качестве имени файла (от 20080101.csv до 20111031.csv) в папке. Файлы CSV имеют общие заголовки. CSV-файл выглядит следующим образом:

 20080101.csv  
X ;Y; Z  
1 ; 1 ; 3  
1 ; 2 ; 6  
1 ; 3 ; 24  
2 ; 1 ; 24  
2 ; 2 ; 24  

20080102.csv   
X ;Y; Z  
1 ; 1 ; 0.1  
1 ; 2 ; 2  
1 ; 3 ; 67  
2 ; 1 ; 24  
2 ; 2 ; 24  

20080103.csv  
X ;Y; Z  
1 ; 1 ; 3  
1 ; 3 ; 24  
2 ; 1 ; 24  
2 ; 2 ; 24  

20080104.csv   
X ;Y; Z  
1 ; 1 ; 34  
1 ; 2 ; 23  
1 ; 3 ; 67  
2 ; 1 ; 24  
2 ; 2 ; 24  
  

… и так далее. Я хочу написать скрипт, который будет считывать строки, и если в данной строке у нас есть X = 1 и Y = 2, вся строка копируется в новый файл CSV вместе с именем файла, дающим следующий вывод:

 X ;Y ; Z ; filename  
1  ; 2 ; 6 ; 20080101  
1  ; 2 ; 2 ; 20080102  
1  ; 2 ; NA; 20080103  
1  ; 2 ; 23; 20080104 
  

Любая идея, как это можно сделать, и любые предложения о модулях, которые я должен изучить, или какие-либо примеры.
Спасибо за ваше время и помощь.

Приветствия, Навин

Комментарии:

1. вас не интересуют записи, чьи (x, y) не являются (1,2)? просто выбросить их?

2. Вы действительно можете назвать файл, разделенный точкой с запятой, csv?

3. @Danny Значения, разделенные символами? С этим я хватаюсь за соломинку 🙂

4. Я видел один, разделенный чертой, почему бы не поставить точку с запятой. кто-нибудь хочет заменить запятую для любой цели, которая у них есть

5. хммм … странное домашнее задание … Чему я могу научиться из этого упражнения?

Ответ №1:

Это правильно сформулированный вопрос, из которого логика должна быть очевидной. Для кого-то предоставление готового кода не соответствовало бы цели назначения. Сначала добавьте к вопросу тег «домашнее задание», затем подумайте о том, что вы хотите сделать: 1) выполните цикл по файлам (отслеживая каждое имя файла по мере его открытия) 2) прочитайте строки из текущего файла 3) если критерии выбора (x == 1 и y == 2) выполнены, затем напишите строку.

Для начала попробуйте:

 import csv, os

for fn in os.listdir():
    if ".csv" in fn:
        with open(fn, 'r', newline='') as f:
            reader = csv.reader(f, delimiter=";")
            for row in reader:
                ...
  

Затем расширьте решение, чтобы открыть выходной файл и записать выбранные строки с помощью csv.writer.

Ответ №2:

Это должно выполнить работу:

 import glob
import os

outfile = open('output.csv', 'w')
outfile.write('X ; Y ; Z ; filenamen')
for filename in glob.glob('*.csv'):
  if filename == 'output.csv': # Skip the file we're writing.
    continue
  with open(filename, 'r') as infile:
    count = 0 
    lineno = 0 
    for line in infile:
      lineno  = 1
      if lineno == 1: # Skip the header line.
        continue
      fields = line.split(';')
      x = int(fields[0])
      y = int(fields[1])
      z = float(fields[2])
      if x == 1 and y == 2:
        outfile.write('%d ; %d ; %g ; %sn' % (x, y, z, filename))
        count  = 1
    if count == 0: # Handle the case when no lines were found.
      outfile.write('1 ; 2 ; NA ; %sn' % filename)
outfile.close()
  

Обратите внимание, что если вы не можете контролировать формат файла или доверять ему, вы можете захотеть обрабатывать исключения, возникающие при преобразовании в int / float.

Комментарии:

1. большое вам спасибо … извините за поздний ответ .. будучи новичком, мне потребовалось некоторое время, чтобы понять каждый ценный ответ. Изучать python действительно весело !!

Ответ №3:

Вы могли бы читать в каждом файле одновременно. Прочитайте это построчно

 files = ['20080101.csv', '20080102.csv', '20080103.csv'] #...etc
for f in files:
    file = open(f, 'r')
    for line in file:
        ray = line.split(';')
        if (ray[0].strip() == '1' and ray[1].strip() == '2'):
            fout = open('output.csv', 'a')
            fout.write(ray[0].strip()   ' ; '   ray[1].strip()   ' ; '   ray[2].strip()   ' ; '   f   'n')
            fout.close()
    file.close()
  

Протестировано и работает. Возможно, потребуются некоторые небольшие изменения.

Комментарии:

1. If всегда завершается ошибкой, поскольку ray является строковым списком.

2. @AdamZalcman: Я проверил этот код, и он работает. ray — это список строк. Я разделяю каждую строку до номера, а затем сравниваю ее с ‘1’ и ‘2’. Пожалуйста, проверьте это и скажите мне, что вы получаете ошибку, прежде чем сообщать мне, что это неправильно.

3. Когда я писал комментарий, вы сравнивали с целыми числами 1 и 2.

4. @AdamZalcman ваш комментарий был написан через 2 минуты после моего последнего редактирования. Но я не буду с вами спорить. Приведенный выше код теперь работает так, как должен.

5. Вы правы, ваша правка была до моего комментария. Я не перезагружал страницу. Кроме того, код действительно работает.

Ответ №4:

если вы знаете, что у вас есть один файл на каждый день, без пропущенных дней, тогда я бы использовал glob (‘*.csv’), чтобы получить список имен файлов, открыть один, пока один, затем прочитать, как это делает Тайлер

если вы знаете, что бывают дни, когда файл отсутствует, я бы использовал datetime для начала с datetime.date (2008,1,1) и увеличивал цикл на один день. затем для каждого дня я составляю имя файла, используя .strftime() ‘.csv’, и пытаюсь обработать файл (если файла нет, просто напишите перекодировку с помощью NA)

Ответ №5:

Должно работать следующее:

 import csv
with open('output.csv', 'w') as outfile:
    outfile.write('X ; Y ; Z ; filenamen')
    fmt = '1 ; 2 ; %s ; %sn'
    files = ['20080101.csv', '20080102.csv', '20080103.csv', '20080104.csv']
    for file in files:
        with open(file) as f:
            reader = csv.reader(f, delimiter=';')
            for row in reader:
                if len(row) > 2 and row[0].strip() == '1' and row[1].strip() == '2':
                    outfile.write(fmt % (row[2].strip(), file[:-4]))
                    break
            else:
                outfile.write(fmt % ('NA', file[:-4]))