Поворот по группам и объединение в Pandas данных - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть два кадра данных, company_df и car_df. Компания может иметь несколько автомобилей, а автомобиль может иметь только одну компанию.

Company_DF

   Company_ID Company_Name
0           1         Ford
1           2       Holden
2           3          Kia

Car_DF

   Company_ID  Car_ID   Car_Name
0           1       1     Falcon
1           1       2      Focus
2           2       1  Commodore
3           3       1    Sorento
4           3       2        Rio
5           3       2   Sportage

У Rio и Sportage одинаковые Car_ID включены цель, примерно у 1 процента моих строк есть эта проблема, это не то, что я могу изменить в своем источнике данных.

Я хотел бы повернуть каждую группу автомобилей, по компании, так, чтобы автомобили все на одной линии. Например.

   Company_ID Company_Name  Car_ID_1 Car_Name_1  Car_ID_2 Car_Name_2  Car_ID_3  Car_Name_3
0           1         Ford         1     Falcon       2        Focus       NaN         NaN
1           2       Holden         1  Commodore       NaN        NaN       NaN         NaN
2           3          Kia         1    Sorento         2        Rio         2    Sportage

То, что у меня есть на данный момент, работает для 99 строк, медленно, и грязный способ сделать это. Но я не уверен, как улучшить это.

import pandas as pd
company_df = pd.DataFrame([[1, 'Ford'], [2, 'Holden'], [3, 'Kia']], columns=['Company_ID', 'Company_Name'])
car_df = pd.DataFrame([[1, 1, 'Falcon'], [1, 2, 'Focus'], [2, 1, 'Commodore'], [3, 1, 'Sorento'], [3, 2, 'Rio'], [3, 2, 'Sportage']], columns=['Company_ID', 'Car_ID', 'Car_Name'])
for i in range(1, 3): # looping through car ids up to maximum, I don't want to do this though
    car_by_id_df = car_df[car_df.Car_ID==i] # select cars with current loop iterator/index
    car_by_id_df.columns = map(lambda col: '{}_{}'.format(col, i), car_by_id_df.columns) # rename all columns with ID as suffix, 
    car_by_id_df.rename(columns={'Company_ID_{}'.format(i): 'Company_ID'}, inplace=True) # Rename joining column back to original
    company_df = company_df.merge(right=car_by_id_df, on='Company_ID', how='left') # Merge
print(company_df)

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

   Company_ID Company_Name  Car_ID_1 Car_Name_1  Car_ID_2 Car_Name_2
0           1         Ford         1     Falcon       2        Focus
1           2       Holden         1  Commodore       NaN        NaN
2           3          Kia         1    Sorento       2          Rio
3           3          Kia         1    Sorento       2     Sportage

Как я могу повернуть car_df по группам и влиться в company_id?

Ответы [ 2 ]

1 голос
/ 15 апреля 2020

Это поможет:

res=Car_DF.set_index("Company_ID").stack().to_frame()

res["sub_no"]=res.groupby(level=[0,1]).cumcount().add(1).astype(str)

res=res.reset_index(level=1)
res["level_1"]=res["level_1"].str.cat(res["sub_no"], sep="_")

res=res.drop("sub_no", axis=1).set_index("level_1", append=True).unstack("level_1")
res.columns=map(lambda x: x[1], res.columns)
res=res[sorted(res.columns, key=lambda x: x.split("_")[-1])]
res=Company_DF.merge(res, on="Company_ID", how="left")

Выходы:

  Company_ID Company_Name  ... Car_ID_3 Car_Name_3
0          1         Ford  ...      NaN        NaN
1          2       Holden  ...      NaN        NaN
2          3          Kia  ...        2   Sportage
0 голосов
/ 17 апреля 2020

Нашел решение. Мне не нравится использование for l oop, но оно работает и относительно быстро.

import pandas as pd
Company_DF = pd.DataFrame([[1, 'Ford'], [2, 'Holden'], [3, 'Kia']], columns=['Company_ID', 'Company_Name'])
Car_DF = pd.DataFrame([[1, 1, 'Falcon'], [1, 2, 'Focus'], [2, 1, 'Commodore'], [3, 1, 'Sorento'], [3, 2, 'Rio'], [3, 2, 'Sportage']], columns=['Company_ID', 'Car_ID', 'Car_Name'])

Car_DF['rank'] = Car_DF.groupby(['Company_ID']).cumcount() + 1
for ranking_number in range(Car_DF['rank'].min(), Car_DF['rank'].max()):
    Ranked_Car_DF = Car_DF[Car_DF['rank']==ranking_number].copy()
    Ranked_Car_DF.columns = map(lambda col: '{}_{}'.format(col, ranking_number), Ranked_Car_DF.columns)
    Ranked_Car_DF.rename(columns={'Company_ID_{}'.format(ranking_number): 'Company_ID'}, inplace=True)
    Company_DF = Company_DF.merge(right=Ranked_Car_DF, on='Company_ID', how='left')
print(Company_DF)
...