Pandas: как извлечь и вычислить количество «часов» на строку в фрейме данных

#python #pandas #dataframe #feature-engineering

#python #pandas #фрейм данных #разработка функций

Вопрос:

У меня есть фрейм данных, представляющий расписание некоторых ресторанов на неделю.

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

Данные (сгенерированные с df.head(20).to_dict('split') помощью)

Дни недель в этом примере указаны на французском языке введите описание изображения здесь

 {'index': [0,
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9,
  10,
  11,
  12,
  13,
  14,
  15,
  16,
  17,
  18,
  19],
 'columns': ['restaurant_id',
  'lundi',
  'mardi',
  'mercredi',
  'jeudi',
  'vendredi',
  'samedi',
  'dimanche'],
 'data': [['lCwqJWMxvIUQt1Re_tDn4w',
   '0:0-0:0',
   '0:0-0:0',
   '0:0-0:0',
   '0:0-0:0',
   '0:0-0:0',
   '0:0-0:0',
   '0:0-0:0'],
  ['pd0v6sOqpLhFJ7mkpIaixw',
   '11:0-20:0',
   '11:0-20:0',
   '11:0-20:0',
   '11:0-20:0',
   '11:0-22:0',
   '11:0-22:0',
   '11:0-17:0'],
  ['0vhi__HtC2L4-vScgDFdFw',
   '11:30-22:0',
   '11:30-22:0',
   '11:30-22:0',
   '11:30-22:0',
   '11:30-22:0',
   '12:0-22:0',
   '16:30-21:30'],
  ['t65yfB9v9fqlhAkLnnUXdg',
   '11:30-21:0',
   '11:30-21:0',
   '11:30-21:0',
   '11:30-21:0',
   '11:30-21:0',
   nan,
   '11:30-21:0'],
  ['i7_JPit-2kAbtRTLkic2jA',
   '11:30-22:0',
   '11:30-22:0',
   '11:30-23:0',
   '11:30-23:0',
   '11:30-23:0',
   nan,
   nan],
  ['vMh4madPU3qhNX7P7d8WGA', nan, nan, nan, nan, nan, nan, nan],
  ['BsvCTCVG7lrzXZ68VyyIcg',
   '0:0-0:0',
   '11:0-2:30',
   '11:0-2:30',
   '11:0-2:30',
   '11:0-2:30',
   '11:0-2:30',
   '11:0-2:30'],
  ['es3Fq9KNp6Ry994x4T4ZYg',
   '6:30-16:0',
   '6:30-16:0',
   '6:30-16:0',
   '6:30-16:0',
   '6:30-16:0',
   '7:0-14:0',
   nan],
  ['Xb7jOAa17xtT_uA4sCCAsg', nan, nan, nan, nan, nan, nan, nan],
  ['1vrrpIhpK628PUA0XWWd8g',
   '9:0-18:0',
   '9:0-18:0',
   '9:0-18:0',
   '9:0-18:0',
   '9:0-18:0',
   '9:0-18:0',
   '9:0-18:0'],
  ['NYKxikYKbkacWumJ82TxzA',
   '11:0-2:0',
   '11:0-2:0',
   '11:0-2:0',
   '11:0-2:0',
   '11:0-2:0',
   '11:0-2:0',
   '11:0-2:0'],
  ['4sRJvmKh43AqMRrjdwEdwA',
   '11:0-22:0',
   '11:0-22:0',
   '11:0-22:0',
   '11:0-22:0',
   '11:0-23:0',
   '11:0-23:0',
   '11:0-23:0'],
  ['laac2uH1lQVzBjKFUjuA1Q',
   '7:0-14:0',
   '7:0-14:0',
   '7:0-14:0',
   '7:0-14:0',
   '7:0-14:0',
   '7:0-14:0',
   '8:0-14:0'],
  ['vVOoL5H8Fr-qlQv-_DdoMA',
   '10:0-22:0',
   '10:0-22:0',
   '10:0-22:0',
   '10:0-22:0',
   '10:0-23:0',
   '10:0-23:0',
   '10:0-22:0'],
  ['k1c4gg8Ri5dre6ruPUKxJQ',
   '9:0-21:30',
   '9:0-21:30',
   '9:0-21:30',
   '9:0-21:30',
   '9:0-22:30',
   '9:0-22:30',
   '12:0-21:0'],
  ['x9f9NBMweyyjCQHuc9K4sw',
   '11:0-17:0',
   '10:0-17:0',
   '10:0-17:0',
   '10:0-17:0',
   '10:0-18:0',
   '10:0-18:0',
   nan],
  ['KWfLQddMBZNoh1bVcgASfA',
   '12:0-23:0',
   '12:0-23:0',
   '12:0-23:0',
   '12:0-23:0',
   '12:0-23:0',
   '12:0-23:0',
   '12:0-23:0'],
  ['4ScLXRii_WwBn5PbGBI-eg', nan, nan, nan, nan, nan, nan, nan],
  ['LAswzVTnT3uCvnKr-SwxEg', nan, nan, nan, nan, nan, nan, nan],
  ['G_wqVaqV3TBsZPAIIRCU-Q',
   '5:0-0:0',
   '5:0-0:0',
   '5:0-0:0',
   '5:0-0:0',
   '5:0-0:0',
   '5:0-0:0',
   '5:0-0:0']]}
  

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

Если нужны какие-либо разъяснения или более простой пример, пожалуйста, спросите.

Редактировать — попробовал решение, указанное ниже, но результаты не имеют значения (например, в первой строке?) введите описание изображения здесь

Ответ №1:

Я думаю, это должно сделать ваше дело. Он сохраняет новые данные в виде числа с плавающей запятой (в часах). С datetime помощью (https://docs.python.org/3/library/datetime.html ) вы можете легко рассчитать время, если захотите. Это применяет функцию calculate_hours к 7 заданным столбцам (дням):

 def calculate_hours(row: pd.Series) -> float:
    try:
        # split the given times to start and end time
        opening_time, closing_time = row.split("-")
        # split hours and minutes
        start_hour, start_minute = opening_time.split(":")
        end_hour, end_minute = closing_time.split(":")
        # calculate start time (in hours)
        start_time = float(start_hour)   float(start_minute) / 60
        # calculate end time (in hours)
        end_time = float(end_hour)   float(end_minute) / 60
        # handle overneight and 24h openings
        if start_time >= end_time:
            end_time  = 24
        # return the duration from start time to end time
        return end_time - start_time
    # bare except are not recommended, you should look for your data, what could go wrong
    except:
        return 0.0


# Save the given data to the new column "open"
# sums up values for each day
df["open"] = df["lundi"].apply(calculate_hours)  
             df["mardi"].apply(calculate_hours)  
             df["mercredi"].apply(calculate_hours)  
             df["jeudi"].apply(calculate_hours)  
             df["vendredi"].apply(calculate_hours)  
             df["samedi"].apply(calculate_hours)  
             df["dimanche"].apply(calculate_hours)
  

PS: Я использовал это для «импорта» ваших данных, это выглядит не идеально, но я не знал, как лучше использовать ваши данные:

 import pandas as pd
import datetime

all = {'index': [0,
                  1,
                  2,
                  3,
                  4,
                  5,
                  6,
                  7,
                  8,
                  9,
                  10,
                  11,
                  12,
                  13,
                  14,
                  15,
                  16,
                  17,
                  18,
                  19],
        'columns': ['restaurant_id',
                    'lundi',
                    'mardi',
                    'mercredi',
                    'jeudi',
                    'vendredi',
                    'samedi',
                    'dimanche'],
        'data': [['lCwqJWMxvIUQt1Re_tDn4w',
                  '0:0-0:0',
                  '0:0-0:0',
                  '0:0-0:0',
                  '0:0-0:0',
                  '0:0-0:0',
                  '0:0-0:0',
                  '0:0-0:0'],
                 ['pd0v6sOqpLhFJ7mkpIaixw',
                  '11:0-20:0',
                  '11:0-20:0',
                  '11:0-20:0',
                  '11:0-20:0',
                  '11:0-22:0',
                  '11:0-22:0',
                  '11:0-17:0'],
                 ['0vhi__HtC2L4-vScgDFdFw',
                  '11:30-22:0',
                  '11:30-22:0',
                  '11:30-22:0',
                  '11:30-22:0',
                  '11:30-22:0',
                  '12:0-22:0',
                  '16:30-21:30'],
                 ['t65yfB9v9fqlhAkLnnUXdg',
                  '11:30-21:0',
                  '11:30-21:0',
                  '11:30-21:0',
                  '11:30-21:0',
                  '11:30-21:0',
                  None,
                  '11:30-21:0'],
                 ['i7_JPit-2kAbtRTLkic2jA',
                  '11:30-22:0',
                  '11:30-22:0',
                  '11:30-23:0',
                  '11:30-23:0',
                  '11:30-23:0',
                  None,
                  None],
                 ['vMh4madPU3qhNX7P7d8WGA', None, None, None, None, None, None, None],
                 ['BsvCTCVG7lrzXZ68VyyIcg',
                  '0:0-0:0',
                  '11:0-2:30',
                  '11:0-2:30',
                  '11:0-2:30',
                  '11:0-2:30',
                  '11:0-2:30',
                  '11:0-2:30'],
                 ['es3Fq9KNp6Ry994x4T4ZYg',
                  '6:30-16:0',
                  '6:30-16:0',
                  '6:30-16:0',
                  '6:30-16:0',
                  '6:30-16:0',
                  '7:0-14:0',
                  None],
                 ['Xb7jOAa17xtT_uA4sCCAsg', None, None, None, None, None, None, None],
                 ['1vrrpIhpK628PUA0XWWd8g',
                  '9:0-18:0',
                  '9:0-18:0',
                  '9:0-18:0',
                  '9:0-18:0',
                  '9:0-18:0',
                  '9:0-18:0',
                  '9:0-18:0'],
                 ['NYKxikYKbkacWumJ82TxzA',
                  '11:0-2:0',
                  '11:0-2:0',
                  '11:0-2:0',
                  '11:0-2:0',
                  '11:0-2:0',
                  '11:0-2:0',
                  '11:0-2:0'],
                 ['4sRJvmKh43AqMRrjdwEdwA',
                  '11:0-22:0',
                  '11:0-22:0',
                  '11:0-22:0',
                  '11:0-22:0',
                  '11:0-23:0',
                  '11:0-23:0',
                  '11:0-23:0'],
                 ['laac2uH1lQVzBjKFUjuA1Q',
                  '7:0-14:0',
                  '7:0-14:0',
                  '7:0-14:0',
                  '7:0-14:0',
                  '7:0-14:0',
                  '7:0-14:0',
                  '8:0-14:0'],
                 ['vVOoL5H8Fr-qlQv-_DdoMA',
                  '10:0-22:0',
                  '10:0-22:0',
                  '10:0-22:0',
                  '10:0-22:0',
                  '10:0-23:0',
                  '10:0-23:0',
                  '10:0-22:0'],
                 ['k1c4gg8Ri5dre6ruPUKxJQ',
                  '9:0-21:30',
                  '9:0-21:30',
                  '9:0-21:30',
                  '9:0-21:30',
                  '9:0-22:30',
                  '9:0-22:30',
                  '12:0-21:0'],
                 ['x9f9NBMweyyjCQHuc9K4sw',
                  '11:0-17:0',
                  '10:0-17:0',
                  '10:0-17:0',
                  '10:0-17:0',
                  '10:0-18:0',
                  '10:0-18:0',
                  None],
                 ['KWfLQddMBZNoh1bVcgASfA',
                  '12:0-23:0',
                  '12:0-23:0',
                  '12:0-23:0',
                  '12:0-23:0',
                  '12:0-23:0',
                  '12:0-23:0',
                  '12:0-23:0'],
                 ['4ScLXRii_WwBn5PbGBI-eg', None, None, None, None, None, None, None],
                 ['LAswzVTnT3uCvnKr-SwxEg', None, None, None, None, None, None, None],
                 ['G_wqVaqV3TBsZPAIIRCU-Q',
                  '5:0-0:0',
                  '5:0-0:0',
                  '5:0-0:0',
                  '5:0-0:0',
                  '5:0-0:0',
                  '5:0-0:0',
                  '5:0-0:0']]}


data = all["data"]
df = pd.DataFrame(data)
df.columns = all["columns"]
  

Комментарии:

1. о, хорошо, я думаю, я понимаю, что вы сделали, но я в замешательстве, как можно манипулировать часами как датами и вычитать их. можете ли вы немного подробнее объяснить, что вы сделали в calculate_hours ? кроме того, я получаю AttributeError: объект ‘float’ не имеет атрибута ‘split’, когда я пытаюсь его запустить

2. и как я могу вывести общее количество часов обратно в новый столбец?

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

4. ошибка с плавающей запятой возникла из NAN в наборе данных. Итак, я попробовал ваше решение, но в новом столбце «открыть» результаты не имеют значения. Я добавил скриншот в свой пост, чтобы вы могли его увидеть. Мне нужно общее количество часов в неделю.

5. я изменил на float , так что это может быть проще для вас. На моей машине вторая строка выдает 2 days 16:00:00 (что правильно), а теперь 64 то же самое в часах.