Как pandas обрабатывает квадратные скобки [] и как этого избежать?

Мне нужно прочитать журнал доступа tomcat, в котором есть такие строки:

    [06/Nov/2020:00:43:04 +0200] /wsi/services/ServicesReadRequest  2265 10.101.101.101 200 21

пытаясь прочитать файл как csv, установив все столбцы как строковый тип

    import pandas as pd 

    headers = ['Timestamp', 'Command', 'IPAddr', 'Blank01', 'Blank02', 
       'Bytes', 'HTTPResult', 'ElapsedTime']
    dtypes = {'Timestamp': 'str',  'Command': 'str', 'IPAddr': 'str', 'Blank01' : 'str', 
       'Blank02' : 'str', 'Bytes': 'str', 'HTTPResult': 'str', 'ElapsedTime': 'str'} 

    df = pd.read_csv(fpath, delimiter=' ', header=None, names=headers, 
       dtype=dtypes, warn_bad_lines=True, error_bad_lines=False)

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

    df['Timestamp'].head()

показывает:

    [06/Nov/2020:00:43:04 +0200] /wsi/services/ServicesReadRequest

если я попытаюсь обрезать строку, похоже, что часть с квадратной скобкой игнорируется

    df["Timestamp"].apply(lambda x: x[1:6]).head()

полученные результаты:

    [06/Nov/2020:00:43:04 +0200] /wsi/s

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


person Tamas Deak    schedule 01.03.2021    source источник
comment
Похоже, ваш столбец Timestamp непреднамеренно стал индексом вашего DataFrame. Попробуйте добавить аргумент index_col=False к вашему вызову pd.read_csv.   -  person jfaccioni    schedule 01.03.2021
comment
Я получаю неизвестный тип строки с форматом, использующим pd.to_datetime. вы пробовали анализировать с помощью strptime   -  person Golden Lion    schedule 02.03.2021
comment
Спасибо! index_col=False решил проблему. Мне пришлось добавить больше столбцов, чтобы заставить его работать, но теперь он работает, как и ожидалось.   -  person Tamas Deak    schedule 03.03.2021


Ответы (2)


Я проанализировал строку в компонентах даты и времени, используя словарь и подстановку регулярных выражений. см.(можете ли вы написать str.replace( ) с использованием значений словаря в Python?), затем преобразовал строку в дату и время, а затем добавил timedelta

 data=["06/Nov/2020:00:43:04 +0200"]
 df=pd.DataFrame(data,columns=['date'])
 def MonthToNum(val):
      dictMonth={'Jan':'1', 'Feb':'2','Mar':'3','Apr':'4','May':'5','Jun':'6','Jul':'7','Aug':'8','Sep':'9','Oct':'10','Nov':'11','Dec':'12'}
      pattern = '|'.join(sorted(re.escape(k) for k in dictMonth))
      retval=re.sub(pattern, lambda m: dictMonth.get(m.group(0)), val, flags=re.IGNORECASE)
     return retval

 df['date']=df['date'].apply(lambda x: pd.to_datetime(MonthToNum(x[0:11])+" "+x[12:20]) + timedelta(int(x[20:24])))
 print(df)
 print(type(df['date']))

выход:

  date
0 2020-06-13 00:43:04
person Golden Lion    schedule 02.03.2021
comment
теперь вы можете использовать дату и преобразовать ее в строку, используя datetime.strptime с %Y-%m-%d %h:%m:%s' - person Golden Lion; 02.03.2021

Решение состояло в том, чтобы добавить index_col=False в команду read_csv и добавить еще несколько столбцов, отметку времени можно преобразовать в дату и время.

    headers = ['Timestamp', 'Timezone', 'Command', 'Blank01', 'IPAddr', 
       'Blank02', 'Blank03', 'Bytes', 'HTTPResult', 'ElapsedTime']
    dtypes = {'Timestamp': 'str', 'Timezone' : 'str', 'Command': 'str', 
       'Blank01' : 'str', 'IPAddr': 'str', 'Blank02' : 'str', 'Blank03' : 'str', 
       'Bytes': 'str', 'HTTPResult': 'str', 'ElapsedTime': 'str'}

    df = pd.read_csv(fpath, delimiter=' ', index_col=False, header=None, 
       names=headers, dtype=dtypes, warn_bad_lines=True, error_bad_lines=False)
       
    df['Timestamp'] =  pd.to_datetime(df['Timestamp'], format='[%d/%b/%Y:%H:%M:%S', 
       errors='coerce')
    idx4 = df['Timestamp'].isna();
person Tamas Deak    schedule 03.03.2021