Разница индексов не работает в Pandas

У меня есть данные за 1 год, которые представляют собой почасовые данные временных рядов, поэтому между ними отсутствует несколько временных меток. Форма этих данных: (8188, 3) образец данных, который я прикрепил ниже.

Я выполняю повторную выборку временных меток в соответствии с продолжительностью моих данных, что приведет к созданию всех временных меток за один год, даже которые отсутствовали в моих исходных данных df_hourly = temp_df.resample('h').asfreq() форма повторной выборки индекса: (8764, 1)

Теперь я беру разницу между повторной выборкой данных и исходными данными new_rows = df_hourly.index.difference(original_index), поэтому фактическая форма индекса должна иметь вид (8764-8188 = 576), а затем я заменю эти 576 отсутствующих временных меток медианой общего числа.

temp_df = temp_df[temp_df['cell'] == cell]
print(temp_df.head())
temp_df.to_csv('temp_df.csv')
print(temp_df.shape)
# get_missing_duplicates(temp_df)
# fill_missing_duplicates()
print(temp_df.shape)
temp_df['_time'] = pd.to_datetime(temp_df['_time'])
print(temp_df['_time'].dtype)
temp_df.set_index('_time', inplace=True)
original_index = temp_df.index
print(original_index)
print("original_index",original_index.shape)
df_hourly = temp_df.resample('h').asfreq()
print(df_hourly)

# This line is not working as expected
new_rows = df_hourly.index.difference(original_index)

print("&&&&&&&&&&&&",original_index)
median_value = df['Total'].median()

# new_rows = df_hourly.index.difference(temp_df.index)
print("new_rows",new_rows)

new_rows = df_hourly.index.difference(original_index) эта строка дает неправильный результат, в основном она должна возвращать разницу df_hourly.index и

  • форма temp_df выглядит как (8188,)
  • форма df_hourly будет иметь вид (8764,)
  • форма new_rows также будет иметь вид (8764,)

Результат temp_df.index:

DatetimeIndex(['2023-05-22 02:00:04+00:00', '2023-05-22 03:00:03+00:00',
               '2023-05-22 04:00:03+00:00', '2023-05-22 05:00:03+00:00',
               '2023-05-22 06:00:03+00:00', '2023-05-22 07:00:03+00:00',
               '2023-05-22 08:00:03+00:00', '2023-05-22 09:00:03+00:00',
               '2023-05-22 10:00:03+00:00', '2023-05-22 11:00:03+00:00',
               ...
               '2024-05-20 17:00:03+00:00', '2024-05-20 18:00:04+00:00',
               '2024-05-20 20:00:03+00:00', '2024-05-20 21:00:03+00:00',
               '2024-05-20 22:00:03+00:00', '2024-05-20 23:00:03+00:00',
               '2024-05-21 01:00:03+00:00', '2024-05-21 02:00:03+00:00',
               '2024-05-21 04:00:03+00:00', '2024-05-21 05:00:03+00:00'],
              dtype='datetime64[ns, UTC]', name='_time', length=8188, freq=None) 

Результат df_hourly.index:

df_hourly_index RangeIndex(start=0, stop=8764, step=1)
(8764, 3)

Образец данных:

Можете ли вы предоставить небольшой пример данных (несколько строк), в которых ваша проблема все еще возникает? Кроме того, необходимо предоставить только соответствующий код (например, все вызовы plot() в вашем вопросе не нужны), чтобы люди могли его протестировать. Часто, пытаясь предоставить минимальный, воспроизводимый пример для StackOverflow, вы сами обнаруживаете и решаете проблему.

steliosbl 27.05.2024 11:46
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
205
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Хотя я еще не совсем понял проблему, и, как уже упоминалось, некоторые примеры строк, а также распечатки ошибок будут полезны. Но я думаю, нам нужно использовать temp_df['Total'].median() вместо df['Total'].median(). Кроме того, кажется, что здесь много избыточности.

temp_df.reset_index(inplace=True)

temp_df['_time'] = pd.to_datetime(temp_df['_time'], utc=True)

# Filtering by cell if needed
cell = 'A'
temp_df = temp_df[temp_df['cell'] == cell]

# Ensuring '_time' is the index and sorted
temp_df.set_index('_time', inplace=True)
temp_df = temp_df.sort_index()

# Saving the original index
original_index = temp_df.index

# Resample the data to get all hourly timestamps
df_hourly = temp_df.resample('H').asfreq()

# Calculate the median value for filling
median_value = temp_df['Total'].median()

# Identify the missing timestamps
new_rows = df_hourly.index.difference(original_index)

# Fill in the missing timestamps with the median value
df_hourly.loc[new_rows, 'Total'] = median_value

# Reset the index if needed
df_hourly.reset_index(inplace=True)

# Save the result
df_hourly.to_csv('df_hourly.csv')

print("Original DataFrame shape:", temp_df.shape)
print("Resampled DataFrame shape:", df_hourly.shape)
print("Missing timestamps shape:", new_rows.shape)
print(df_hourly.head(10))
Original DataFrame shape: (16376, 2)
Resampled DataFrame shape: (8190, 3)
Missing timestamps shape: (2,)
                      _time cell  Total
0 2023-05-22 00:00:00+00:00    A    0.0
1 2023-05-22 01:00:00+00:00    A    1.0
2 2023-05-22 02:00:00+00:00    A    2.0
3 2023-05-22 03:00:00+00:00    A    3.0
4 2023-05-22 04:00:00+00:00    A    4.0
5 2023-05-22 05:00:00+00:00    A    5.0
6 2023-05-22 06:00:00+00:00    A    6.0
7 2023-05-22 07:00:00+00:00    A    7.0
8 2023-05-22 08:00:00+00:00    A    8.0
9 2023-05-22 09:00:00+00:00    A    9.0

new_rows = df_hourly.index.difference(original_index) в основном эта строка работает неправильно.

Ravi kant Gautam 28.05.2024 07:33
Ответ принят как подходящий

pandas 2.2.1

Проблема с повторной выборкой неоднородных временных меток

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

'2023-05-22 02:00:04+00:00' - 4 seconds after 2:00 
'2023-05-22 03:00:03+00:00' - 3 seconds after 3:00

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

temp_df['_time'] = pd.to_datetime(temp_df['_time'], utc=True).dt.round('h')

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

new_rows = df_hourly.index[temp_df.resample('h').size() == 0]

Если по какой-то причине нам нужно сохранить исходные временные метки, то я думаю, что asfreq() может быть не лучшим выбором; использование first() выглядит более разумным. Также я бы добавил в этом случае некоторое отрицательное смещение при повторной выборке, на тот случай, если некоторые записи были сделаны за несколько секунд до окончания часа, примерно так:

df_hourly = temp_df.resample('h', offset=pd.Timedelta('-5min')).first()

Если причина поиска разницы между временными метками, подвергнутыми повторной выборке, и исходными состоит в заполнении пробелов, вместо этого мы можем использовать fillna(...).

Код для экспериментов

Следующий пример данных был взят из исходного сообщения с одним изменением, чтобы представить возможную проблему (см. «За секунду до…» в коде и понятие о параметре offset= для resample):

import pandas as pd

timestamps = [
    '2024-05-20 17:00:03+00:00', 
    '2024-05-20 18:00:04+00:00',
    # missing
    '2024-05-20 20:00:03+00:00', 
    '2024-05-20 20:59:59+00:00',     # a second before 21:00:00
    '2024-05-20 22:00:03+00:00', 
    '2024-05-20 23:00:03+00:00',
    # missing
    '2024-05-21 01:00:03+00:00',
    '2024-05-21 02:00:03+00:00',
    # missing
    '2024-05-21 04:00:03+00:00',
    '2024-05-21 05:00:03+00:00'
]

values = [403, 369, 375, 394, 398, 372, 335, 385, 415, 383]

df = pd.DataFrame({
    'time': pd.to_datetime(timestamps, utc=True), 
    'value': values}
)

Вариант 1. Сохраните исходные временные метки (без округления).

five_min = pd.Timedelta('5min')
grouped_by_hour = df.set_index('time').resample('h', offset=-five_min)

resampled_data = grouped_by_hour.first()
is_new_record = grouped_by_hour.size() == 0

resampled_data.loc[is_new_record, 'value'] = round(df['value'].median())
resampled_data['value'] = resampled_data.astype({'value': int})
resampled_data.index += five_min

print('Resampled_data'.upper(),
      resampled_data,
      '\nNew records'.upper(),
      resampled_data.index[is_new_record],
      sep='\n')

Вариант 2. Перед повторной выборкой округлите временные метки до ближайшего часа.

rounded_original_time = df['time'].dt.round('h')
resampled_data = (
    df[['value']]
    .set_index(rounded_original_time)
    .resample('h')
    .asfreq()
)
new_records = resampled_data.index.difference(rounded_original_time)
resampled_data.loc[new_records, 'value'] = round(df['value'].median())

print('Resampled_data'.upper(),
      resampled_data,
      '\nNew records'.upper(),
      new_records,
      sep='\n')

Другие вопросы по теме