Как сопоставить данные из одного фрейма данных в столбец в другом фрейме данных?

avatar
user10525916
9 августа 2021 в 02:56
63
1
2

У меня есть два отдельных фрейма данных, представляющих разные типы данных, основанных на времени. Один содержит сотни тысяч временных меток, разбросанных по нескольким месяцам. Этот кадр данных имеет столбцы, представляющие месяц года, время суток и измеренную температуру. Второй кадр данных состоит из замещающих температур для каждой комбинации месяц/час. Данные выглядят примерно так:

df1

Временная метка Месяц Час Температура
01.01.2021 00:00:00 1 0 10
01.01.2021 00:00:05 1 0 11
01.01.2021 00:00:07 1 0 8
01.01.2021 00:00:15 1 0 12
01.01.2021 00:01:00 1 1 13

и т.д.

df2

Час Янв февраль март апр и т.д.
0 9 12 10 12 и т.д.
1 10 11 14 15 и т.д.
2 8 7 12 16 и т.д.

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

Мне нужно сопоставить данные, содержащиеся за месяц/час в df2, со столбцом Temperature в df 1. Таким образом, df1 после редактирования должен выглядеть следующим образом.

Новый df1

Временная метка Месяц Час Температура
01.01.2021 00:00:00 1 0 9
01.01.2021 00:00:05 1 0 9
01.01.2021 00:00:07 1 0 9
01.01.2021 00:00:15 1 0 9
01.01.2021 00:01:00 1 1 10

Я заставил его работать, используя вложенный цикл for, следующим образом:

for month in df2.columns:
    for hour in df2.index:
        dT = df2.loc[hour, month]
        df1.loc[(df1['Month'] == month) & (df1['Hour'] == hour), 'Temperature'] = dT

Вложенный цикл for перебирает все месяцы и часы в df2, находит ячейки в df1 с соответствующими месяцем и часом, затем устанавливает температуру, равную температуре, считанной из df2.

Но этот код сложно читать и очень медленно выполнять. Кто-нибудь знает лучший способ??

Спасибо!

Источник
mozway
9 августа 2021 в 03:38
0

Можете ли вы проверить мой ответ и дать мне отзыв о времени работы? Можно сделать это быстрее, пропустив шаг по извлечению названия месяца и вместо этого переработав второй фрейм данных. Дай мне знать…

Ответы (1)

avatar
mozway
9 августа 2021 в 03:36
1

Давайте назовем df1 и df2 ваши два фрейма данных по порядку.

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

df1['Timestamp'] = pd.to_datetime(df1['Timestamp'])
df1['Month_name'] = df1['Timestamp'].dt.month_name().str[:3]

Примечание. если скорость имеет решающее значение, пропустите указанный выше шаг и переработайте df2, чтобы номера месяцев использовались вместо названий месяцев в качестве столбцов, а затем на последнем шаге используйте столбец «Месяц» df1 для выполнения слияния

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

df2.set_index('Hour').unstack().rename('Temperature')

Наконец, merge два:

df1.merge(df2.set_index('Hour').unstack().rename('Temperature'),
          left_on=['Month_name', 'Hour'],
          right_index=True,
          suffixes=('_old', ''),
         )

вывод:

            Timestamp  Month  Hour  Temperature_old Month_name  Temperature
0 2021-01-01 00:00:00      1     0               10        Jan            9
1 2021-01-01 00:00:05      1     0               11        Jan            9
2 2021-01-01 00:00:07      1     0                8        Jan            9
3 2021-01-01 00:00:15      1     0               12        Jan            9
4 2021-01-01 00:01:00      1     1               13        Jan           10

Если вы хотите сохранить только новые температуры, добавьте .drop(['Month', 'Temperature_old'], axis=1)

user10525916
11 августа 2021 в 14:23
0

Привет Мозвей. Спасибо за предложение! К сожалению, это не работает. Когда я запускаю шаг .merge, я получаю сообщение об ошибке, в котором говорится, что он пытается объединить столбцы int и object, и вместо этого я должен использовать pd.concat. Вот конкретная ошибка: ValueError: вы пытаетесь объединить столбцы int32 и object. Если вы хотите продолжить, вы должны использовать pd.concat. Я очень смущен этой ошибкой, потому что, когда я проверяю типы столбцов, они выстраиваются в линию. Месяц — целое число (например, «Янвь» теперь равно «1»). Час внутр. Индекс df2.unstack().rename('Temperature') является кортежем, но и left_on тоже. есть идеи?

mozway
11 августа 2021 в 14:36
0

Почему индекс является кортежем? Ваш набор данных отличается от примера? Вы можете это предоставить?

user10525916
12 августа 2021 в 00:30
0

Проблема возникает при распаковке df2. Первоначально «час» - это индекс (приношу свои извинения за то, что не указал это изначально). Когда я распаковываю, он становится многоуровневым индексом (месяц, час). Но код, который вы предоставили, выглядит так, как будто он ожидает кортеж, поэтому я не ожидаю, что это будет проблемой. Я могу загрузить df2, но не df1. Есть ли хороший способ сделать это? Я никогда раньше не задавал вопрос о SO и не вижу четкого способа сделать это.