Чтение и организация CSV без модулей?

#python #pandas #csv

#python #панды #csv

Вопрос:

У меня есть несколько разных файлов csv с разным количеством заголовков. Мне нужно прочитать эти csv без использования каких-либо модулей, поэтому я предпринял попытку. Как мне распечатать столбцы разных CSV, а затем получить среднее, минимальное, максимальное и стандартное отклонение для каждого из них, а также сопоставить их друг с другом?

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

Я могу использовать pandas, как только я записал csv в фрейм данных python, поэтому я его импортировал. Любые рекомендации или идеи приветствуются. Спасибо!

 import pandas as pd

def readmyfile(InputFile):
    
    list_date = []
    list_baro = []
    
    with open(InputFile, 'r') as file:
        for line in file:
            row = line.split(',')
            list_date.append(row[0].strip('"'))
            list_baro.append(row[1].strip('n'))
    
#     df = pd.DataFrame(list_date[1:])
#     df2 = pd.DataFrame(list_baro[1:])
#     average = np.mean(df2)
    
    print(list_date)
    print(list_baro)
    
readmyfile('barometer-last-year.csv')
  

Некоторые данные, которые есть в barometer-last-year.csv:

 "DateTime","Baro"
"2016-10-09 00:00:00",1021.9
"2016-10-10 00:00:00",1019.9
"2016-10-11 00:00:00",1015.8
"2016-10-12 00:00:00",1013.2
"2016-10-13 00:00:00",1005.9
"2016-10-14 00:00:00",998.6
"2016-10-15 00:00:00",998
"2016-10-16 00:00:00",1002.2
"2016-10-17 00:00:00",1009.8
"2016-10-18 00:00:00",1013.4
"2016-10-19 00:00:00",1015.8
"2016-10-20 00:00:00",1015.7
  

и вот некоторые данные, которые у меня есть в других CSV:

 "DateTime","Temperature","Temperature_range (low)","Temperature_range (high)"
"2016-10-09 00:00:00",10.66,7.2,13.8
"2016-10-10 00:00:00",8.94,5.6,12.8
"2016-10-11 00:00:00",8.69,5.3,14.3
"2016-10-12 00:00:00",11.55,9,14.9
"2016-10-13 00:00:00",9.4,6,13.3
"2016-10-14 00:00:00",9.85,6.8,13.3
"2016-10-15 00:00:00",10.72,8.2,14.7
"2016-10-16 00:00:00",11.28,7.8,14.5
"2016-10-17 00:00:00",11.84,10,15
"2016-10-18 00:00:00",10.24,8.2,12.7
"2016-10-19 00:00:00",10.2,8,13.4
"2016-10-20 00:00:00",9.76,7.2,12.8
"2016-10-21 00:00:00",7.96,3.7,15.1
"2016-10-22 00:00:00",7.9,5.3,13
  

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

1. Можете ли вы предоставить некоторые примеры данных из файлов csv, чтобы структура данных была очевидной?

2. Конечно, позвольте мне отредактировать его.

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

4. Я хочу иметь возможность выводить максимальное и минимальное значение volumns (кроме даты и времени) вместе со средним и средним значением каждого из них. Тогда в идеале нарисуйте их, чтобы у меня было что-то визуальное для их сравнения.

5. Вы хотите загрузить разные CSV-файлы, а затем отобразить их на временной шкале, чтобы показать изменение различных параметров во времени?

Ответ №1:

Я реализовал parse_csv() функцию внутри следующего кода, который не использует модули. Он поддерживает любой разделитель (например , ) между ячейками и любой символ, заключенный в кавычки (например " ), также он корректно обрабатывает разделители, расположенные внутри строк, заключенных в кавычки, например, строка CSV "a,b,c",d будет обрабатываться как две ячейки a,b,c и d . Пустые строки в CSV пропускаются.

Первая строка обрабатывается как имена столбцов. Функция возвращает имена столбцов и остальные строки отдельно, так что эти два могут быть переданы непосредственно pd.DataFrame() конструктору.

Функция принимает header аргумент (имена столбцов), он должен быть True , если строка заголовка должна считываться как первая строка файла CSV, он должен быть False или содержать список имен столбцов, если в файле CSV нет строки заголовка.

Входной файл CSV может быть передан функции различными способами 1) Через file аргумент, который может быть либо строкой, содержащей путь к файлу или имя, либо открытым для чтения объектом file. 2) text Аргумент Through, который может быть либо строкой, содержащей текст CSV, либо байтами, содержащими содержимое файла CSV.

В простейшей форме вы просто делаете columns, table = parse_csv(file = 'test.csv') .

Попробуйте онлайн!

 def parse_csv(*, file = None, text = None, sep = ',', quote = '"', header = True, encoding = 'utf-8'):
    assert file is not None or text is not None, f'Either text or file argument should be provided!'
    if text is None:
        if type(file) is str:
            with open(file, 'r', encoding = encoding) as f:
                text = f.read()
        elif type(file) is bytes:
            text = file
        else:
            text = file.read()
    if type(text) is bytes:
        text = text.decode(encoding)
    first, ncols, table = True, None, []
    for line in text.splitlines():
        line = line.strip()
        if not line:
            continue
        parts = line.split(sep)
        i = 0
        entries = []
        while True:
            if i >= len(parts):
                break
            if not parts[i].startswith(quote):
                entries.append(parts[i])
                i  = 1
            else:
                entries.append(parts[i][len(quote):])
                while True:
                    if parts[i].endswith(quote):
                        entries[-1] = entries[-1][:-len(quote)]
                        break
                    i  = 1
                    entries[-1]  = sep   parts[i]
                i  = 1
        if first:
            if header is True:
                hrow = True
                header = entries
                ncols = len(entries)
            elif header is False:
                hrow = False
                header = None
                ncols = len(entries)
            else:
                hrow = False
                assert type(header) in [list, tuple], type(header)
                header = list(header)
                ncols = len(header)
            first = False
        else:
            hrow = False
        if not hrow:
            assert len(entries) == ncols, f'Wrong number of columns (expected {ncols}) in row: {line}'
            table.append(entries)
            
    if first and type(header) is bool:
        header = None
    return header, table

    
import pandas as pd



# ----- First example -----

text = """

"DateTime","Temperature","Temperature_range (low)","Temperature_range (high)"

"2016-10-09 00:00:00",10.66,7.2,13.8
"2016-10-10 00:00:00",8.94,5.6,12.8
"2016-10-11 00:00:00",8.69,5.3,14.3
"2016-10-12 00:00:00",11.55,9,14.9
"2016-10-13 00:00:00",9.4,6,13.3
"2016-10-14 00:00:00",9.85,6.8,13.3
"2016-10-15 00:00:00",10.72,8.2,14.7
"2016-10-16 00:00:00",11.28,7.8,14.5
"2016-10-17 00:00:00",11.84,10,15
"2016-10-18 00:00:00",10.24,8.2,12.7
"2016-10-19 00:00:00",10.2,8,13.4
"2016-10-20 00:00:00",9.76,7.2,12.8
"2016-10-21 00:00:00",7.96,3.7,15.1
"2016-10-22 00:00:00",7.9,5.3,13

"""

columns, table = parse_csv(text = text)
df = pd.DataFrame(table, columns = columns)
print('-' * 30)
print(df)



# ----- Second example -----

text = """
    a|b|'c|d'|e
    
    1|2|3|4
"""

ref = None
for header in [
    True, False, ['first', 'second', 'third', 'fourth'],
]:
    columns, table = parse_csv(text = text, sep = '|', quote = "'", header = header)
    df = pd.DataFrame(table, columns = columns)
    print('-' * 30)
    print(df)
    if ref is None:
        ref = (columns, table)
    
    
# ----- Third example -----

import io

with open('test.csv', 'w', encoding = 'utf-8') as f:
    f.write(text)

for file in [
    io.StringIO(text), io.BytesIO(text.encode('utf-8')), text.encode('utf-8'),
    'test.csv', open('test.csv', 'r', encoding = 'utf-8'), open('test.csv', 'rb'),
]:
    columns, table = parse_csv(file = file, sep = '|', quote = "'")
    assert (columns, table) == ref
  

Вывод:

 ------------------------------
               DateTime Temperature Temperature_range (low) Temperature_range (high)
0   2016-10-09 00:00:00       10.66                     7.2                     13.8
1   2016-10-10 00:00:00        8.94                     5.6                     12.8
2   2016-10-11 00:00:00        8.69                     5.3                     14.3
3   2016-10-12 00:00:00       11.55                       9                     14.9
4   2016-10-13 00:00:00         9.4                       6                     13.3
5   2016-10-14 00:00:00        9.85                     6.8                     13.3
6   2016-10-15 00:00:00       10.72                     8.2                     14.7
7   2016-10-16 00:00:00       11.28                     7.8                     14.5
8   2016-10-17 00:00:00       11.84                      10                       15
9   2016-10-18 00:00:00       10.24                     8.2                     12.7
10  2016-10-19 00:00:00        10.2                       8                     13.4
11  2016-10-20 00:00:00        9.76                     7.2                     12.8
12  2016-10-21 00:00:00        7.96                     3.7                     15.1
13  2016-10-22 00:00:00         7.9                     5.3                       13
------------------------------
   a  b c|d  e
0  1  2   3  4
------------------------------
   0  1    2  3
0  a  b  c|d  e
1  1  2    3  4
------------------------------
  first second third fourth
0     a      b   c|d      e
1     1      2     3      4
  

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

1. Ах, это имеет гораздо больше смысла. Что касается ввода текста, есть ли способ, которым я могу ввести CSV непосредственно в него без необходимости превращать его в текст? Спасибо!

2. В настоящее время функция @Nhyi имеет дело только с входной текстовой строкой. Вам просто нужно прочитать свой входной файл самостоятельно, просто сделайте: with open('file_name.csv', 'r', encoding = 'utf-8') as f: columns, table = parse_csv(f.read()) . Или вы можете добавить эту логику чтения файлов в начало моей функции.

3. Ах, я попробую и дам вам знать, что произойдет. Я собирался добавить его в начало функции, но не приведет ли это к тому, что splitlines() станет проблемой?

4. @Nhyi Теперь я изменю свою функцию, чтобы она могла поддерживать различные типы ввода (текст, файл и т. Д.).

5. Приветствую, очень признателен. Я определенно понимаю, как вы можете поместить его вне функции, просто объединив его с функцией parse_csv, с чем у меня сейчас возникают проблемы.