Как объединить два кадра данных по общему столбцу на основе словаря?

#python #dataframe #dictionary #join #merge

Вопрос:

итак, у меня есть два кадра данных, которые я пытаюсь объединить в один столбец. Однако этот общий столбец отличается между обоими кадрами данных, где значения в одном кадре данных являются полными именами, а значения в другом кадре данных являются сокращениями. Я пытаюсь создать своего рода словарь сопоставлений, который приравнивает имена к их аббревиатурам, чтобы фреймы данных могли быть непосредственно объединены этим общим столбцом. Я объясню подробнее ниже.

У меня есть этот фрейм данных (A):

     Building         Style           CO2       NOx
---------------------------------------------------
Multi-Family             A            34        55
Multi-Family             B            43        44
Multi-Family             C            33        35 
Single-Family            A            34        26
Single-Family            B            22        26
Single-Family            C            65        48
Single-Family            D            55        74 
Studio                   A            46        35 
Studio                   B            54        67
Studio                   C            57        58
 

И затем у меня есть этот фрейм данных (B):

 Building   Style    Zip_code     Number
---------------------------------------
      MF       A       11111         4 
      MF       A       22222         3
      MF       A       33333         2
      MF       B       11111         1
      MF       B       22222         1
      MF       C       22222         1 
      MF       C       33333         6
      SF       A       11111         7 
      SF       A       22222         5
      SF       B       44444         3
      SF       B       55555         8 
      SF       B       66666         6
      SF       C       11111         9
      SF       C       22222         9
      ST       A       33333         3
      ST       A       44444         5
      ST       B       55555         5
      ST       B       66666         3
      ST       C       11111         2 
      ST       C       22222         9 
      ST       C       33333         1
 

Теперь я хочу создать следующий фрейм данных (C):

 Zip_code      CO2    NOx
-------------------------
11111           ?      ?
22222           ?      ?
33333           ?      ?
44444           ?      ?
55555           ?      ?
66666           ?      ?
 

Я объясню это дальше. У меня есть данные по зданиям, которые показывают выбросы CO2 и NOx для 3 стилей зданий, соответствующих 3 типам зданий (кадр данных A). Затем у меня есть данные, которые показывают, сколько домов каждого из этих типов находится в каждом из перечисленных почтовых индексов (Фрейм данных B). В конечном счете я хочу создать фрейм данных, который показывает общие выбросы для каждого почтового индекса, как для CO2, так и для NOx (Фрейм данных C). Идея получения фрейма данных C заключается в том, что я хочу создать фрейм данных, который затем может быть присоединен к шейп-файлу ГИС по почтовому индексу, чтобы затем я мог отобразить выбросы CO2 и NOx в каждом почтовом индексе, получив пустой шейп-файл zipcodes для присоединения. (Я понимаю, что картирование выбросов намного сложнее, чем это, но я сохраняю это простым для данного этапа моего проекта).

Поэтому я пытаюсь соединить фрейм данных A с фреймом данных B в столбце «Здание». Проблема, однако, заключается в том, что столбец «Здание» в кадре данных A содержит имена полностью, в то время как столбец «Здание» в кадре данных B содержит имена в виде сокращений. Я думаю, что мне нужно создать какой-то словарь, который сопоставит полное название с его аббревиатурой, на которую следует ссылаться, но я не уверен, как это сюда вписать.

Можно ли это сделать на python? Или это на самом деле намного сложнее, чем я себе это представляю? Я потратил много часов на то, чтобы понять, как объединить эти два кадра данных, но с каждым разом я все больше запутываюсь. У меня много проблем с концептуализацией того, как будет выглядеть этот код, даже если цель может показаться простой. Я был бы признателен за любую помощь или руководство в этом! Приношу извинения за то, что сделал эти кадры данных такими длинными, но я чувствовал, что необходимо отразить структуру/сложность данных.

Спасибо!

Ответ №1:

Это, безусловно, возможно. Вы действительно можете сначала превратить названия зданий в аббревиатуры, используя пользовательскую функцию, которая разбивается на дефис и принимает первую букву каждого слова. Затем вы можете объединить кадры данных на обоих Building и Style . Наконец-то вы можете groupby на Zip-code :

 import pandas as pd

data1 = [ { "Building": "Multi-Family", "Style": "A", "CO2": 34, "NOx": 55 }, { "Building": "Multi-Family", "Style": "B", "CO2": 43, "NOx": 44 }, { "Building": "Multi-Family", "Style": "C", "CO2": 33, "NOx": 35 }, { "Building": "Single-Family", "Style": "A", "CO2": 34, "NOx": 26 }, { "Building": "Single-Family", "Style": "B", "CO2": 22, "NOx": 26 }, { "Building": "Single-Family", "Style": "C", "CO2": 65, "NOx": 48 }, { "Building": "Single-Family", "Style": "D", "CO2": 55, "NOx": 74 }, { "Building": "Studio", "Style": "A", "CO2": 46, "NOx": 35 }, { "Building": "Studio", "Style": "B", "CO2": 54, "NOx": 67 }, { "Building": "Studio", "Style": "C", "CO2": 57, "NOx": 58 } ]
data2 = [ { "Building": "MF", "Style": "A", "Zip_code": 11111, "Number": 4 }, { "Building": "MF", "Style": "A", "Zip_code": 22222, "Number": 3 }, { "Building": "MF", "Style": "A", "Zip_code": 33333, "Number": 2 }, { "Building": "MF", "Style": "B", "Zip_code": 11111, "Number": 1 }, { "Building": "MF", "Style": "B", "Zip_code": 22222, "Number": 1 }, { "Building": "MF", "Style": "C", "Zip_code": 22222, "Number": 1 }, { "Building": "MF", "Style": "C", "Zip_code": 33333, "Number": 6 }, { "Building": "SF", "Style": "A", "Zip_code": 11111, "Number": 7 }, { "Building": "SF", "Style": "A", "Zip_code": 22222, "Number": 5 }, { "Building": "SF", "Style": "B", "Zip_code": 44444, "Number": 3 }, { "Building": "SF", "Style": "B", "Zip_code": 55555, "Number": 8 }, { "Building": "SF", "Style": "B", "Zip_code": 66666, "Number": 6 }, { "Building": "SF", "Style": "C", "Zip_code": 11111, "Number": 9 }, { "Building": "SF", "Style": "C", "Zip_code": 22222, "Number": 9 }, { "Building": "ST", "Style": "A", "Zip_code": 33333, "Number": 3 }, { "Building": "ST", "Style": "A", "Zip_code": 44444, "Number": 5 }, { "Building": "ST", "Style": "B", "Zip_code": 55555, "Number": 5 }, { "Building": "ST", "Style": "B", "Zip_code": 66666, "Number": 3 }, { "Building": "ST", "Style": "C", "Zip_code": 11111, "Number": 2 }, { "Building": "ST", "Style": "C", "Zip_code": 22222, "Number": 9 }, { "Building": "ST", "Style": "C", "Zip_code": 33333, "Number": 1 } ]
df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)

def shorten_buildings(text):
    text = ''.join([i[0] for i in text.split('-')])
    return text if text != 'S' else 'ST'

df1['Building'] = df1['Building'].apply(shorten_buildings)

df2 = df2.merge(df1,  how='left', on=['Building','Style'])

df2['CO2'] = df2['Number'] * df2['CO2'] #total CO2
df2['NOx'] = df2['Number'] * df2['NOx'] #total NOx
df2.groupby(['Zip_code']).sum().drop('Number', axis=1)
 

Выход:

Почтовый индекс CO2 NOx
11111 1116 994
22222 1446 1328
33333 461 483
44444 296 253
55555 446 543
66666 294 357