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

#pandas #dataframe #join #merge

Вопрос:

Я считываю данные из файла xlsx с помощью pandas — и создаю фрейм данных для каждой рабочей книги, найденной в файле xlsx, и содержащей, например, данные о рабочих местах людей, образовании людей и предыдущем опыте работы людей. таким образом, в конце я работаю примерно с 13 кадрами данных. все фреймы данных имеют общий столбец «talent_id», с помощью которого они могут быть объединены (объединены) в какой-то более поздний момент. проблема, с которой я в настоящее время сталкиваюсь, заключается в том, что в df1 идентификатор таланта уникален, в df2 «идентификатор таланта» не уникален из-за того, что в прошлом у людей могло быть несколько образований (поэтому каждая работа, которую они выполняли ранее, является наблюдением), то же самое с df3, который дает мне весь предыдущий опыт работы для каждого отдельного «идентификатора таланта».

Итак, чего я пытаюсь достичь, в конце концов, у меня есть один df, который содержит всю информацию из df1, df2 и df3 без дублированных строк «talent_id», а не по 1 строке на «talent_id» и столбцы для всех образовательных организаций и бывших работодателей в виде столбцов или функций.

Вот код для создания df — я возился с melt(), join(), merge (), давая мне не то, что я хотел.

Излишне говорить, что не у каждого talent_id одинаковое количество учебных заведений, некоторые посещали 2 школы, некоторые 2 школы и 3 колледжа и т. Д., Поэтому количество функций варьируется, равно как и количество предыдущего опыта работы.

 data1 = [['001', '1975-01-01', 'mr', 'de', 'at', 40000], ['002', '1980-01-01', 'mrs', 'en', 'uk', 50000], ['003', '1985-01-01', 'mr', 'es', 'es', 45000]]
df1 = pd.DataFrame(data1, columns = ['talent_id',  'birthdate', 'salutation', 'nationality', 'country', 'salary'])
 
data2 = [['001', 'groundschool_a', 'NaN', 'basic', 'none', 'yes'], ['001', 'high_school', 'math', 'higher', 'none', 'no'], ['002', 'groundschool_b', 'NaN', 'basic', 'none', 'yes'],
        ['002', 'highschool', 'science', 'higher', 'yes', 'yes'], ['002', 'college', 'medicine', 'degree', 'MA', 'yes'], ['003', 'NA', 'none', 'dont know', 'none', 'NaN']]
df2 = pd.DataFrame(data2, columns = ['talent_id',  'schoolname', 'subject', 'type_of_education', 'degree', 'completed'])

data3 = [['001', 'company_a', 'supervisor', 'manufacturing'], ['001', 'company_b', 'editor', 'educational'], ['002', 'company_c', 'clerk', 'pos'],
        ['002', 'company_d', 'cleaning', 'steel'], ['002', 'company_e', 'ceo', 'sales'], ['003', 'company_f', 'it', 'retail']]
df3 = pd.DataFrame(data3, columns = ['talent_id',  'company', 'position', 'industry'])
 

В идеале приемлемый результат был бы примерно таким:

 data4 = [['001', '1975-01-01', 'mr', 'de', 'at', 40000, 
          'groundschool_a', 'NaN', 'basic', 'none', 'yes', 'high_school', 'math', 'higher', 'none', 'no', 
          'company_a', 'supervisor', 'manufacturing', 'company_b', 'editor', 'educational', 'NA','NA','NA','NA','NA', 'NA', 'NA', 'NA'], 
         ['002', '1980-01-01', 'mrs', 'en', 'uk', 50000, 
          'groundschool_b', 'NaN', 'basic', 'none', 'yes', 'highschool', 'science', 'higher', 'yes', 'yes', 'college', 'medicine', 'degree', 'MA', 'yes',
          'company_c', 'clerk', 'pos', 'company_d', 'cleaning', 'steel', 'company_e', 'ceo', 'sales'], 
         ['003', '1985-01-01', 'mr', 'es', 'es', 45000, 'NA', 'none', 'dont know', 'none', 'NaN',
          'company_f', 'it', 'retail', 'NA','NA','NA','NA','NA','NA','NA','NA','NA','NA', 'NA', 'NA', 'NA', 'NA', 'NA', 'NA']]


df4 = pd.DataFrame(data4, columns = ['talent_id', 'birthdate', 'salutation', 'nationality', 'country', 'salary', 
                                    'schoolname_1', 'subject_1', 'type_of_education_1', 'degree_1', 'completed_1', 
                                    'schoolname_2', 'subject_2', 'type_of_education_2', 'degree_2', 'completed_2',
                                    'schoolname_3', 'subject_3', 'type_of_education_3', 'degree_3', 'completed_3',
                                    'company_1', 'position', 'industry',
                                    'company_2', 'position', 'industry',
                                    'company_2', 'position', 'industry'])

 

желаемый результат df

Я думал о том, чтобы проанализировать каждый df для определенного «talent_id», записать его в список и, в конце концов, сделать df из этого списка, но есть ли более разумный и эффективный способ сделать это ?

Ответ №1:

Сначала создайте небольшую вспомогательную функцию для обработки ваших фреймов данных 2 и 3:

 def group_pivot(d):
    d =(d.assign(group=d.groupby('talent_id').cumcount())
         .pivot(index='talent_id', columns='group', values=d.columns[1:])
        )
    d.columns = ['_'.join(map(str, c)) for c in d.columns]
    return d.reset_index()
 

пример на df3:

 >>> group_pivot(df3)
  talent_id  company_0  company_1  company_2  position_0 position_1 position_2     industry_0   industry_1 industry_2
0       001  company_a  company_b        NaN  supervisor     editor        NaN  manufacturing  educational        NaN
1       002  company_c  company_d  company_e       clerk   cleaning        ceo            pos        steel      sales
2       003  company_f        NaN        NaN          it        NaN        NaN         retail          NaN        NaN
 

Затем объедините все преобразованные кадры данных в «talent_id».:

 df1.merge(group_pivot(df2), on='talent_id').merge(group_pivot(df3), on='talent_id')
 

выход:

   talent_id   birthdate salutation nationality country  salary    schoolname_0 schoolname_1 schoolname_2 subject_0 subject_1 subject_2 type_of_education_0 type_of_education_1 type_of_education_2 degree_0 degree_1 degree_2 completed_0 completed_1 completed_2  company_0  company_1  company_2  position_0 position_1 position_2     industry_0   industry_1 industry_2
0       001  1975-01-01         mr          de      at   40000  groundschool_a  high_school          NaN       NaN      math       NaN               basic              higher                 NaN     none     none      NaN         yes          no         NaN  company_a  company_b        NaN  supervisor     editor        NaN  manufacturing  educational        NaN
1       002  1980-01-01        mrs          en      uk   50000  groundschool_b   highschool      college       NaN   science  medicine               basic              higher              degree     none      yes       MA         yes         yes         yes  company_c  company_d  company_e       clerk   cleaning        ceo            pos        steel      sales
2       003  1985-01-01         mr          es      es   45000              NA          NaN          NaN      none       NaN       NaN           dont know                 NaN                 NaN     none      NaN      NaN         NaN         NaN         NaN  company_f        NaN        NaN          it        NaN        NaN         retail          NaN        NaN
 

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

1. Большое вам спасибо, я провел несколько тестов с помощью вспомогательной функции, которую вы придумали, — кажется, это хорошо работает — в настоящее время я запускаю это на образце набора данных с 500 строками, и это довольно быстро. производственный набор данных содержит примерно 40 тысяч строк — будем с нетерпением его ждать … ценю ваше время и усилия, чтобы помочь мне …

Ответ №2:

Вы можете использовать следующий groupby метод agg для создания списка из переменных, таких как образование в вашем примере. Например:

 df2.groupby('talent_id').agg({
   'education':list
    })
 

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

Примечание: Метод groupby создает talent_id индекс, поэтому используйте соответствующие параметры в merge методе для объединения ваших фреймов данных вместе.