Более эффективный способ извлечения временных данных из строки (или объекта DataFrame) - PullRequest
0 голосов
/ 03 ноября 2019

Я изучаю Python самостоятельно, и это мой первый вопрос здесь. Всегда смог найти все необходимое, уже ответил. Наконец-то есть что-то, что я считаю, стоит спросить. Это просто более конкретная задача, которую я даже не знаю, что искать.

Одна из наших машин генерирует файл журнала, который требует большой очистки после загрузки в DataFrame и перед использованием. Не вдаваясь в подробности, файл журнала содержит запись времени в очень странном формате. Это набор минут, секунд и миллисекунд. Я смог декодировать его в считанные секунды с помощью функции, показанной ниже (и затем преобразовать ее в формат времени с другой). Он отлично работает, но это очень простая функция с большим количеством статических меток.

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

Вот примеры всех возможных комбинаций записей времени:

test1 = 'T#3853m10s575ms'   # 231190.575 [seconds]
test2 = 'T#10s575ms'        # 10.575
test3 = 'T#3853m575ms'      # 231180.575
test4 = 'T#575ms'           # 0.575
test5 = 'T#3853m10s'        # 231190
test6 = 'T#10s'             # 10
test7 = 'T#3853m'           # 231180
test8 = 'T#0ms'             # 0

Я пытался записать это вформат регулярного выражения: T#[0-9]*m?[0-9]*s?[0-9]*ms? однако всегда будет присутствовать хотя бы одна цифра и хотя бы одна единица.

Вот логика, которую я использую внутри функции: функциональная схема

А вот функция, которую я применяю к необработанному столбцу времени в DataFrame:

def convert_time(string):
    if string == 'T#0ms':
        return 0
    else:
        ms_ = False if string.find('ms') == -1 else True
        string = string[2:-2] if ms_ else string[2:]
        s_ = False if string.find('s') == -1 else True
        m_ = False if string.find('m') == -1 else True
        if m_ and s_ and ms_:
            m, temp = string.split('m')
            s, ms = temp.split('s')
            return int(m)*60 + int(s) + int(ms)*0.001
        elif not m_ and s_ and ms_:
            s, ms = string.split('s')
            return int(s) + 0.001 * int(ms)
        elif m_ and not s_ and ms_:
            m, ms = string.split('m')
            return 60*int(m) + 0.001 * int(ms)
        elif not m_ and not s_ and ms_:
            return int(string) * 0.001
        elif m_ and s_ and not ms_:
            m, s = string.split('m')
            return 60*int(m) + int(s[:-1])
        elif not m_ and s_ and not ms_:
            return int(string[:-1])
        elif m_ and not s_ and not ms_:
            return int(string[:-1]) * 60
        elif not m_ and not s_ and not ms_:
            return -1

Как упомянуто выше, отсутствие опыта не позволяет мне написать лучшую функцию для результатав аналогичном выводе (или лучше, например, непосредственно в формате времени). Надеюсь, что это будет достаточно интересно, чтобы получить некоторые советы по улучшению. Благодаря.

Ответы [ 2 ]

0 голосов
/ 03 ноября 2019

Использование регулярного выражения:

import re

def f(x):
    x = x[2:]
    time = re.findall(r'\d+', x)
    timeType = re.findall(r'[a-zA-Z]+',x)
    #print(time,timeType)
    total = 0
    for i,j in zip(time,timeType):
        if j == 'm':
            total += 60*float(i) 
        elif j =='s':
            total+=float(i) 
        elif j == 'ms':
            total += float(i)/1000
    return total 

test1 = 'T#3853m10s575ms'   # 231190.575 [seconds]
test2 = 'T#10s575ms'        # 10.575
test3 = 'T#3853m575ms'      # 231180.575
test4 = 'T#575ms'           # 0.575
test5 = 'T#3853m10s'        # 231190
test6 = 'T#10s'             # 10
test7 = 'T#3853m'           # 231180
test8 = 'T#0ms'             # 0

arr = [test1,test2,test3,test4,test5,test6,test7,test8]

for t in arr:
    print(f(t))

Вывод:

231190.575
10.575
231180.575
0.575
231190.0
10.0
231180.0
0.0
[Finished in 0.7s]

Или вы можете уменьшить размер кода, если у вас больше времени, например, час, день и т. Д.
Используйте карту для этого

import re
def symbol(j):
    if j == 'm':
        return 60 
    elif j =='s':
        return 1  
    elif j == 'ms':
        return .001

def f(x):
    x = x[2:]
    time = list(map(float,re.findall(r'\d+', x)))
    timeType = list(map(symbol,re.findall(r'[a-zA-Z]+',x)))
    #print(time,timeType)
    return sum([a*b for a,b in zip(timeType,time)]) 

test1 = 'T#3853m10s575ms'   # 231190.575 [seconds]
test2 = 'T#10s575ms'        # 10.575
test3 = 'T#3853m575ms'      # 231180.575
test4 = 'T#575ms'           # 0.575
test5 = 'T#3853m10s'        # 231190
test6 = 'T#10s'             # 10
test7 = 'T#3853m'           # 231180
test8 = 'T#0ms'             # 0

arr = [test1,test2,test3,test4,test5,test6,test7,test8]

for t in arr:
    print(f(t))
0 голосов
/ 03 ноября 2019
def str_to_sec(time_str):
    return_int = 0
    cur_int = 0

    # remove start characters and replace 'ms' with a single character as unit
    time_str = time_str.replace('T#','').replace('ms', 'p')

    # build multiplier matrix
    split_order = ['m', 's', 'p']
    multiplier = [60, 1, 0.001]
    calc_multiplier_dic = dict(zip(split_order, multiplier))

    # loop through string and update the cumulative time
    for ch in time_str:
        if ch.isnumeric():
            cur_int = cur_int * 10 + int(ch)
            continue
        if ch.isalpha():
            return_int += cur_int * calc_multiplier_dic[ch]
            cur_int = 0

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