Преобразование столбца Pandas данных ISO 8601 в секунды

Я пытаюсь преобразовать столбец данных pandas данных продолжительности ISO 8601 в общее количество секунд. Значения продолжительности выглядят как PT7M7S, что означает 7 минут и 7 секунд. isodate 0.5.4 эффективен при разборе одной строки, если я использую что-то вроде isodate.parse_duration("PT7M7S"). Однако мне нужно запустить ту же команду в столбце pandas, и я понятия не имею, как это сделать. Я пробовал isodate.parse_duration(df2['duration']), но он возвращает TypeError: Expecting a string.

Следующий код создает тестовый фрейм данных:

df = ["PT7M7S", "PT7M14S", "PT6M45S"]
df = pd.DataFrame.from_dict(df)
names = df.columns.tolist()
names[names.index(0)] = 'duration'
df.columns = names

Это код, который я пробовал, но не был эффективным:

import isodate
dur = isodate.parse_duration(df['duration'])
df['duration'] = dur.total_seconds()

Идеальным выходом было бы иметь столбец duration, состоящий из общего количества секунд, соответствующих этой строке. Так, например, вместо первой строки, имеющей PT7M7S, она будет читаться 427.

Я ценю любую помощь. Спасибо.


person Maxwell Poole    schedule 04.11.2016    source источник
comment
dur = df2['duration'].apply(isodate.parse_duration) должно работать, но может быть быстрее просто проанализировать строку, чтобы извлечь компоненты минут и секунд, а затем просто выполнить арифметические действия с этими извлеченными значениями, если у вас много строк для анализа.   -  person EdChum    schedule 05.11.2016
comment
Благодарю вас! Это помещает его в формат hh:mm:ss, а не в общее количество секунд, но я могу с этим работать. Я действительно ценю твою помощь. Если вы хотите отправить это как ответ, я могу выбрать его как принятый ответ.   -  person Maxwell Poole    schedule 05.11.2016


Ответы (3)


Вы можете использовать str.extract для анализа строки:

import numpy as np
import pandas as pd

df = pd.DataFrame({'duration': ["PT7M7S", "PT7M14S", "PT6M45S"]})
df[['minutes','seconds']] = df['duration'].str.extract(r'PT(\d+)M(\d+)S', expand=True).astype('int')
df['total_seconds'] = 60*df['minutes'] + df['seconds']

урожаи

  duration  minutes  seconds  total_seconds
0   PT7M7S        7        7            427
1  PT7M14S        7       14            434
2  PT6M45S        6       45            405
person unutbu    schedule 04.11.2016
comment
Спасибо за ваш ответ. Он отлично работает, когда я запускаю его на своем небольшом образце данных, который я предоставил здесь, но по какой-то причине я получаю следующее в своем большом наборе данных, состоящем примерно из 300 строк. ValueError: cannot convert float NaN to integer - person Maxwell Poole; 05.11.2016
comment
Это означает, что в df['duration'] есть по крайней мере одна строка, не соответствующая шаблону регулярного выражения PT(\d+)M(\d?)S. Мы можем узнать, что эти строки используют df.loc[~df['duration'].str.contains(r'PT(\d+)M(\d+)S')]. - person unutbu; 05.11.2016

Почему бы не использовать функцию apply для серии df['duration'], это было бы намного быстрее.

Вот пример кода.

In [17]: df['duration'] = df['duration'].apply(isodate.parse_duration)
In [18]: df['duration'] = df['duration']/np.timedelta64(1, 's')
In [19]: df
   duration
0     427.0
1     434.0
2     405.0

Обратите внимание, здесь есть одна хитрость: разделите datetime или timedelta объект на np.timedelta64 с другой единицей измерения, вы можете получить номера этой единицы для этого объекта.

Кстати, если у вас есть NaN или пропущенное значение, вам нужно их обработать.

Еще одно упоминание: для ответа от unutbu он подходит только в том случае, если ваши данные содержат только 'M' и 'S'. Поскольку duration_isoformat может быть PnnYnnMnnDTnnHnnMnnS.

Надеюсь, это сработает для вас.

person rojeeer    schedule 04.11.2016

Вот альтернативное решение:

In [53]: (pd.to_datetime(df['duration'], format='PT%MM%SS', errors='coerce') -
    ...:  pd.to_datetime('1900-01-01')).dt.total_seconds()
    ...:
Out[53]:
0    427.0
1    434.0
2    405.0
Name: duration, dtype: float64

Данные:

In [54]: df
Out[54]:
  duration
0   PT7M7S
1  PT7M14S
2  PT6M45S

Объяснение:

In [55]: pd.to_datetime(df['duration'], format='PT%MM%SS', errors='coerce')
Out[55]:
0   1900-01-01 00:07:07
1   1900-01-01 00:07:14
2   1900-01-01 00:06:45
Name: duration, dtype: datetime64[ns]
person MaxU    schedule 04.11.2016