read_csv получить строку, где произошло исключение - PullRequest
0 голосов
/ 07 октября 2018

Файлы журнала HTTP, которые я пытаюсь проанализировать с помощью панд, иногда имеют неожиданные строки.Вот как я загружаю свои данные:

df = pd.read_csv('mylog.log',
            sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])', 
            engine='python', na_values=['-'], header=None,
            usecols=[0, 3, 4, 5, 6, 7, 8,10],
            names=['ip', 'time', 'request', 'status', 'size', 
                'referer','user_agent','req_time'], 
                converters={'status': int, 'size': int, 'req_time': int})

Это прекрасно работает для большинства журналов, которые у меня есть (которые приходят с того же сервера).Однако при загрузке некоторых журналов возникает исключение:

 TypeError: int() argument must be a string, a bytes-like object or a  number, not 'NoneType'

или

ValueError: invalid literal for int() with base 10: '"GET /agent/10577/bdl HTTP/1.1"'

Для примера приведем строку, которая вызывает второе исключение:

22.111.117.229, 22.111.117.229 - - [19/Sep/2018:22:17:40 +0200] "GET /agent/10577/bdl HTTP/1.1" 204 - "-" "okhttp/3.8.0" apibackend.site.fr 429282

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

def search_error_dichotomy(path):    
        borne_inf = 0
        log = open(path)
        borne_sup = len(log.readlines())
        log.close()
        while borne_sup - borne_inf>1:
            exceded = False
            search_index = (borne_inf + borne_sup) // 2
            try:
                pd.read_csv(path,...,...,nrows=search_index)
            except:
                exceded = True
            if exceded:
                borne_sup = search_index
            else:
                borne_inf = search_index

        return search_index

Я хотел бы получить что-то вроде этого:

try:
    pd.read_csv(..........................)
except MyError as e:
    print(e.row_number)

где e.row_number - номер грязной строки.

Заранее спасибо.

РЕШЕНИЕ Все кредиты devssh, чье предложение не только ускоряет процесс, но и позволяет мне сразу получить все неожиданные строки.Вот что я сделал из этого:

  1. Загрузить фрейм данных без конвертеров.

    df = pd.read_csv(path,
                     sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])', 
                     engine='python', na_values=['-'], header=None,
                     usecols=[0, 3, 4, 5, 6, 7, 8,10],
                     names=['ip', 'time', 'request', 'status', 'size',
                     'referer', 'user_agent', 'req_time'])
    
  2. Добавить столбец «index» с помощью .reset_index().

    df = df.reset_index()
    
  3. Напишите пользовательскую функцию (которая будет использоваться с apply), которая преобразует в int, если это возможно, в противном случае сохраняет запись и индекс в словаре неправильных строк

    wrong_lines = {}
    def convert_int_feedback_index(row,col):
        try:
            ans = int(row[col])
        except:
            wrong_lines[row['index']] = row[col]
            ans = pd.np.nan
        return ans
    
  4. Используйте применить к столбцам, которые я хочу преобразовать (например, col = 'status', 'size' или 'req_time')

    df[col] = df.apply(convert_int_feedback_index, axis=1, col=col)
    

1 Ответ

0 голосов
/ 07 октября 2018

Вы пробовали pd.read_csv (..., nrows = 10), чтобы посмотреть, работает ли он хотя бы на 10 строках?

Возможно, вам не следует использовать converters для указания dtypes.Загрузите DataFrame, затем примените dtype к столбцам, таким как df["column"] = df["column"].astype(np.int64), или к пользовательской функции, такой как df["column"]=df["column"].apply(lambda x: convert_type(x)), и обработайте ошибки самостоятельно в функции convert_type.Наконец, обновите CSV, вызвав df.to_csv("preprocessed.csv", headers=True, index=False).Я не думаю, что вы можете получить номер строки от самого pd.read_csv.Сам этот разделитель выглядит слишком сложным.

Или вы можете попробовать просто прочитать csv как отдельный столбец DataFrame и использовать df["column"].str.extract, чтобы использовать регулярное выражение для извлечения столбцов.Таким образом вы управляете тем, как должно вызываться исключение, или значением по умолчанию для обработки ошибки.

df.reset_index() даст вам номера строк в виде столбца.Таким образом, если вы примените к двум столбцам , вы также получите номер строки.Это даст вам индексный столбец с номерами строк.Объедините это с применить к нескольким столбцам, и вы можете настроить все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...