Хвостовой файл, который не начинается с символа - PullRequest
0 голосов
/ 16 февраля 2020

У меня есть набор необработанных CSV-файлов, которые имеют заголовки комментариев (символ #) в дополнение к именам столбцов. Например:

# This data is taken from ....
# ...
# ...
# ...
# col1,col2,...,coln
#
[csv data rows starts here]

Количество строк над строкой, содержащей имена столбцов, не фиксировано для каждого файла.

Как «вырезать» файл (создать новый файл), который будет выводить стандартный формат CSV?

col1,col2,...,coln
[csv data rows starts here]

Я использую блокнот Jupyter для обработки данных, поэтому я заинтересованы в этом как с использованием встроенного сценария оболочки (возможно, используя tail), так и Python.

1 Ответ

1 голос
/ 16 февраля 2020

A Python версия, которая должна работать в вашем ноутбуке Jupyter, приведена ниже. Вам необходимо заменить <file_name> s, перечисленные в строке file_names = ["<file_name1>","<file_name2>"], на ваши.

import os
import sys
import pandas as pd
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO

def mine_header(fn):
    '''
    To answer https://stackoverflow.com/q/60249235/8508004

    Takes a file name as input

    Assumes last commented line with contents before the data rows start 
    contains the column names. Could be condensed, to read in all text once and
    then rsplit on last `#` but going line by line at start offers more 
    opportunity for customizing later if not quite matching pattern seen in 
    data files. Also could just assume second last line above the data contains 
    the column names? In that case, could skip 
    `header = [x for x in header if x]` line and use 
    `col_names = header[-2].split(",")` instead.

    Returns list of column names and rest of contents of csv file beyond
    header.
    '''
    # first copy the input file that will be parsed line by to a new file so
    # can parse contents while possibly overwriting the input file with a
    # shorter version if a label for a set encountered inside it
    beyond_header = False
    header = [] # collect the header lines 
    data_rows = "" # collect the data rows
    # go through the file line by line until beyond commented out header
    with open(fn, 'r') as input:
        for line in input:
            if beyond_header:
                data_rows += line
            elif line.startswith("#"):
                header.append(line[1:].strip()) # leave off comment symbol and 
                # remove any leadding and trailing whitespace
            # If line doesn't start with comment symbol, have hit the end of 
            # the header and want to start collecting the csv data tows
            else:
                data_rows += line
                beyond_header = False
    # Now process the header lines to get the column names.
    header = [x for x in header if x]# The last row before the data should be 
    # empty now and so that list comprehension should remove it leaving last row
    # as the one with the column names
    col_names = header[-1].split(",")
    return col_names, data_rows


file_names = ["<file_name1>","<file_name2>"]
df_dict = {}
for i,fn in enumerate(file_names):
    col_names, data_rows = mine_header(fn)
    df_dict[i] = pd.read_csv(StringIO(data_rows), header=0, names=col_names)

# display the produced dataframes
from IPython.display import display, HTML
for df in df_dict:
    display(df)

A pandas. Для каждого кадра данных доступен индекс, соответствующий списку созданных вами файлов. Например, кадр данных, созданный из третьего CSV-файла, будет иметь вид df_dict[2].

Я взял его за рамки того, что вы просили, поскольку разбиение столбцов в списке было легко спроектировать в функцию интеллектуального анализа и Pandas настроен так, чтобы справляться со всем после этого.
Если вы действительно хотите сделать вывод в качестве стандартного CSV, вы можете использовать col_names и data_rows, возвращаемые col_names, data_rows = mine_header(fn), а также сохранить файл CSV. Вы бы скомбинировали их, чтобы создать строку для сохранения следующим образом:

col_names_as_string = ",".join(col_names)
string_to_save = col_names_as_string + "\n" + data_rows
...