Добавление и заполнение строк в df в соответствии с условиями

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

у меня есть df, подобный этому:

 Timestamp                                 Time  Power    Total Energy              ID     Energy
2020-04-09 06:45:00 2020-04-09 06:40:40.559719   7500       5636690.0               1      140.0    
2020-04-09 06:46:00 2020-04-09 06:40:40.559719   7500       5636710.0               1      160.0    
2020-04-09 06:47:00                        NaT    NaN             NaN             NaN        NaN    
2020-04-09 06:48:00 2020-04-09 06:40:40.559719   7500       5636960.0               1      410.0
2020-04-09 06:49:00                        NaT    NaN             NaN             NaN        NaN
2020-04-09 06:50:00                        NaT    NaN             NaN             NaN        NaN
2020-04-09 06:51:00                        NaT    NaN             NaN             NaN        NaN
...                                        ...    ...             ...             ...        ...
2020-04-30 23:55:00 2020-04-29 16:30:38.559871   7500      18569270.0               5      100.0
2020-04-30 23:54:00                        NaT    NaN             NaN             NaN        NaN
2020-04-30 23:55:00 2020-04-29 16:30:38.559871   7500      18569370.0               5      180.0
  

я должен скорректировать / добавить некоторые значения:

  1. Добавьте строки для df[‘Time’] > df[‘Timestamp’]: df[‘Timestamp’] с интервалом в 1 минуту; df[‘Time’] = ввод df[‘Time’]; df[‘Power’] = df[‘Energy’] / (дельта t (= разница между временем и существующей временной меткой (в часах))); df[‘Total Energy’], df[‘ID’] и df[ ‘Энергия’] lik df[‘время’]
  2. Заполнение значений NaN / NaT в области, где время не меняется (с помощью bfill или ffill)
  3. Заполнение значений NaN / Nat между двумя разными записями df[‘Time’] равными 0, соответственно df[‘Total Energy’] последней записью (ffill)

Ожидаемый результат:

 Timestamp                                 Time  Power    Total Energy              ID     Energy
2020-04-09 06:41:00 2020-04-09 06:40:40.559719   2100       5636690.0               1      140.0    
2020-04-09 06:42:00 2020-04-09 06:40:40.559719   2100       5636690.0               1      140.0    
2020-04-09 06:43:00 2020-04-09 06:40:40.559719   2100       5636690.0               1      140.0    
2020-04-09 06:44:00 2020-04-09 06:40:40.559719   2100       5636690.0               1      140.0
2020-04-09 06:45:00 2020-04-09 06:40:40.559719   7500       5636690.0               1      140.0    
2020-04-09 06:46:00 2020-04-09 06:40:40.559719   7500       5636710.0               1      160.0    
2020-04-09 06:47:00 2020-04-09 06:40:40.559719   7500       5636710.0               1      160.0    
2020-04-09 06:48:00 2020-04-09 06:40:40.559719   7500       5636960.0               1      410.0
2020-04-09 06:49:00                         -       0       5636960.0               -          0
2020-04-09 06:50:00                         -       0       5636960.0               -          0
2020-04-09 06:51:00                         -       0       5636960.0               -          0
...                                        ...    ...             ...             ...        ...
2020-04-30 23:55:00 2020-04-29 16:30:38.559871   7500      18569270.0               5      100.0
2020-04-30 23:54:00 2020-04-29 16:30:38.559871   7500      18569270.0               5      100.0
2020-04-30 23:55:00 2020-04-29 16:30:38.559871   7500      18569370.0               5      180.0
  

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

РЕДАКТИРОВАТЬ: вот пример моего кода:

 df = pd.DataFrame({"Time": ["2020-04-09 06:40:40.559719","2020-04-09 06:40:40.559719", 'NaT', "2020-04-09 06:40:40.559719", 'NaT', 'NaT', 'NaT', '2020-04-09 16:50:38.559871', 'NaT', '2020-04-29 16:50:38.559871'],
              "Power": [7500, 6000, 'NaN', 6000, 'NaN', 'NaN', 'NaN', 3600, 'NaN', 4200],
              "Total Energy": [5000, 5100, 'NaN', 5300, 'NaN', 'NaN', 'NaN', 5360, 'NaN', 5500],
              "ID": [1, 1, 'NaN', 1, 'NaN', 'NaN', 'NaN', 2, 'NaN', 2],
              "Energy": [500, 600, 'NaN', 800, 'NaN', 'NaN', 'NaN', 60, 'NaN', 200]},
              index=pd.date_range(start = "2020-04-09 6:45", periods = 10, freq = 'T'))

df['Time'] = pd.to_datetime(df['Time'])
df['Power'] = pd.to_numeric(df['Power'], errors = 'coerce')
df['Total Energy'] = pd.to_numeric(df['Total Energy'], errors = 'coerce')
df['ID'] = pd.to_numeric(df['ID'], errors = 'coerce')
df['Energy'] = pd.to_numeric(df['Energy'], errors = 'coerce')

df
  

Ожидаемый результат:

                     Time                       Power    Total Energy    ID  Energy
2020-04-09 06:41:00 2020-04-09 06:40:40.559719   0      4500.0          1.0 0
2020-04-09 06:42:00 2020-04-09 06:40:40.559719   7500.0 4625.0          1.0 125.0
2020-04-09 06:43:00 2020-04-09 06:40:40.559719   7500.0 4750.0          1.0 250.0
2020-04-09 06:44:00 2020-04-09 06:40:40.559719   7500.0 4875.0          1.0 375.0
2020-04-09 06:45:00 2020-04-09 06:40:40.559719   7500.0 5000.0          1.0 500.0
2020-04-09 06:46:00 2020-04-09 06:40:40.559719   6000.0 5100.0          1.0 600.0
2020-04-09 06:47:00 2020-04-09 06:40:40.559719   6000.0 5200.0          1.0 700.0
2020-04-09 06:48:00 2020-04-09 06:40:40.559719   6000.0 5300.0          1.0 800.0
2020-04-09 06:49:00 -                           0       5300.0          -   0
2020-04-09 06:50:00 -                           0       5300.0          -   0
2020-04-09 06:51:00 2020-04-09 16:50:38.559871  0       5300.0          2.0 0
2020-04-09 06:52:00 2020-04-09 16:50:38.559871  3600.0  5360.0          2.0 60.0
2020-04-09 06:53:00 2020-04-09 16:50:38.559871  4200.0  5430.0          2.0 130.0
2020-04-09 06:54:00 2020-04-29 16:50:38.559871  4200.0  5500.0          2.0 200.0
  
  1. df[‘Time’]: создавайте новые строки до тех пор, пока df[‘Timestamp’] = df[‘Time’]
  2. Заполняем новые строки: df[‘Energy’] = 0 для первой строки, чем заполняем ее линейно; df[‘Power’] = 0 для первой строки, чем df[‘Power’] = df[‘Energy’]/(1/60); df[‘Time’] и df[‘ID’] заполняем с помощью bfill(); df[‘Total Energy’] = Общая сумма df[‘Energy’]
  3. Строки между двумя разными временами: заполнение в соответствии с ожидаемым результатом
  4. NaN-значения во временном ряду (например, @2020-04-09 06:47:00): df[‘Time’] и df[‘ID’] с помощью ffill(); df[‘Energy’] = разница между существующими строками (если есть больше NaN-строк -> интерполировать линейно); df[‘Total Energy’] = старое значение df [‘Energy’]; df[‘Power’] = df[‘Energy ‘]/(1/60)

спасибо за помощь

Ответ №1:

Мне кажется, что может потребоваться несколько различных функций:

  1. delta t: Может использовать shift() для получения значений опережения или задержки, а затем может вычислить разницу.
  2. Для заполнения значений NaN / NaT можно использовать fillna()
    bfill: df['Column'].fillna(val, method='bfill')
    ffill: df['Column'].fillna(val, method='ffill')
  3. Можно использовать fillna, как указано выше. После этого можно перезаписать столбец новыми значениями на основе условия: np.where(condition, value if condition met, value if condition not met)

Например, чтобы создать столбец «Общая энергия» после завершения работы столбца «энергия», вы могли бы использовать:

 # 1. First fill na with ffill method'
df['Total Energy'].fillna(method='ffill', inplace=True)
# 2. Find deltas
df['energy_delta'] = df['Energy'] - df['Energy'].shift(1)
df['t_energy_delta'] = df['Total Energy'] - df['Total Energy'].shift(1)
# 3. Correct total_energy column to take into account delta
df['Total Energy'] = np.where(df['energy_delta']>df['t_energy_delta'], df['Total Energy'] df['energy_delta'], df['Total Energy'])
  

Это немного многословно, но я думаю, что оно справится с задачей. Вероятно, есть способ получше.

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

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

2. Привет, Вини, я обновил свой ответ, включив в него больше деталей. Если бы вы могли предоставить синтаксис для создания небольшого набора данных, представляющего вашу задачу, было бы проще помочь с точным синтаксисом. В противном случае мой текущий ответ больше похож на общее руководство.

3. Привет, Золзая, я отредактировал свой пост и добавил код, надеюсь, это поможет. Спасибо за вашу помощь!!

4. Спасибо Vini. Мне довольно сложно разобраться в логике. Похоже, что ваше описание логики и ожидаемый результат не согласуются. Например: условие df[‘Power’] = df [‘Energy’] / (1/60), похоже, не выполняется в ожидаемом результате. В первой строке исходные данные имеют мощность 6000, но в ожидаемом выводе она изменилась на 7500. Не пропущенные значения также должны изменяться? Пример данных начинается с 6:45, но ожидаемый вывод начинается немного раньше. Я думаю, вам, возможно, придется более четко указать, чего вы хотите достичь и где вам нужна помощь.

5. Привет, Залзая, спасибо, что потратили время на мою проблему. Вы правы, первые 6000 в df[‘power’] были опечаткой (я исправил ее). второе, что вы поднимаете в связи с датами до 6:45, — это точно то же самое. Я хочу добавить недостающие данные между df[‘Time’] и индексом, или, если строки уже существуют, заполнить их соответствующим образом. Точнее, строки должны быть заполнены из соответствующей записи для df[‘Time’] ( df[‘Time’] == 06:40:40 —> строки из df.index = 06:41:00 должны быть заполнены соответствующим образом).