Эквивалентные группы

В Stata у меня есть данные о людях, которые вместе работали над проектом. Каждая строка представляет собой проект, и есть столбцы от человека_1 до человека_20, и если в этом столбце есть имя, это означает, что человек работал над этим проектом в строке. Группа может быть 1 человек, 2 человека, ..., 20 человек. У меня есть двоичная переменная (да = 1) для каждой возможности: Группа 1 (G1), G2, ..., G11. Затем я использовал этот код для создания групп (на примере группы из 4 человек):

project_group = person_1 + "/" + person_2 + "/" + person_3 + "/" + person_4 if G4 == 1
This yields: Tom/Joe/Mike/Sally

У меня три вопроса: 1) Есть ли более эффективный способ группировки. Например, код, который просто просматривает проект (строку), подсчитывает, сколько в нем людей (сколько непустых полей), а затем создает уникальное имя группы, которое представляет собой имя каждого человека, разделенное знаком «/». Я в порядке с кодом, который я создал, но мой набор данных изменится в размере, и, вероятно, лучше использовать более эффективный код.

2) Как я могу рассматривать, исходя из моего примера, Джо/Тома/Майка/Салли или Салли/Джо/Майка/Тайма как одну и ту же группу. Я бы предпочел, чтобы все группы, независимо от размера, перечисляли каждого человека в алфавитном порядке. В моем примере список будет Джо/Майк/Салли/Том независимо от фактической перестановки.

3) Как сделать группу уникальной на основе первого человека (если это руководитель проекта, то он указан первым). Итак, Джо/Том/Майк и Джо/Майк/Том — это одна и та же группа, а Том/Джо/Майк и Майк/Том/Джо — нет.

Спасибо за помощь и предложения


person CJ12    schedule 20.10.2012    source источник
comment
Я переупорядочил свое решение. Я думаю, что любое масштабируемое решение здесь перекодирует ваши данные, но это можно сделать в цикле, чтобы минимизировать ввод.   -  person Richard Herron    schedule 22.10.2012


Ответы (2)


1) Есть ли более эффективный способ группировки.

Я не уверен, что понимаю, что не так с вашей нынешней аранжировкой, которая кажется чистой и легко читаемой.

2) Как я могу рассматривать, исходя из моего примера, Джо/Тома/Майка/Салли или Салли/Джо/Майка/Тайма как одну и ту же группу.

Я предполагаю, что вы имели в виду Тома, а не Время в вашей последней строке.

egen team_size = anycount(person_1-person_20), v(1)
gen team_leader = .
if team_size > 0 replace team_leader = person_1
gen team_structure = 0
replace team_structure = team_structure + regexm(project_group,"Joe")
replace team_structure = team_structure + regexm(project_group,"Tom")*10
replace team_structure = team_structure + regexm(project_group,"Mike")*100
replace team_structure = team_structure + regexm(project_group,"Sally")*1000

team_structure — это двоичный файл длиной $k$, который кодирует членство в команде из $k$ участников независимо от порядка, в котором они могут отображаться в строке project_group. Это затратно по коду, если у вас много членов, но довольно легко создать.

3) Как сделать группу уникальной на основе первого человека (если это руководитель проекта, то он указан первым). Итак, Джо/Том/Майк и Джо/Майк/Том — это одна и та же группа, а Том/Джо/Майк и Майк/Том/Джо — нет.

Тривиальное предложение: добавьте коэффициент к каждому возможному элементу (encode) и присвойте его десятичной дроби созданной выше переменной team_structure. Пример: 1011.1 — это группа Джо/Майка/Салли во главе с Джо, 1011.4 — та же группа во главе с Салли и так далее.

person Fr.    schedule 22.10.2012

Я изменил свой подход, чтобы быть более ясным. Вы упомянули, что не можете перекодировать свои переменные, но я не уверен, есть ли способ обойти это (я думаю, что любое решение здесь перекодирует явно или неявно). Конечно, вам нужно будет заменить «4» на «20».

* generate some projects and members
clear
set obs 5
generate int project = _n
generate person_1 = "Tom"
generate person_2 = "Dick" if (_n >= 3)
generate person_3 = "Harry" if (_n >=5)
replace person_1 = "Jane" if inlist(_n, 2, 4)
tempfile orig
save `orig'

* reshape to long
reshape long person_, i(project) string
drop _j
drop if missing(person)
sort project person
egen id = group(person)
drop if missing(id)
reshape wide person, i(project) j(id)

* recode to allow easier group identification
forvalues i = 1/4 {
    levelsof person_`i', local(name) clean
    generate byte d_person_`i' = cond(missing(person_`i'), 0, 1)
    label define d_person_`i'_lbl 1 "`name'" 0 ""
    label values d_person_`i' d_person_`i'_lbl
}

* determine number of workers on project
egen gp_size = rowtotal(d_person_*)

* unique id for each group composition
generate int id = 0
forvalues i = 1/4 {
    local two_i = 2^(`i' - 1)
    replace id = id + d_person_`i' * `two_i'
}

* group members
generate str mbrs = ""
forvalues i = 1/4 {
    local name: label d_person_`i'_lbl 1
    replace mbrs = mbrs + "/" + "`name'" if (d_person_`i' == 1)
}   

* there's always a leading "/" to remove with this approach
replace m = substr(m, 2, .)

* merge back your orig data
merge 1:1 project using `orig', nogenerate replace update

Это дает:

. list

     +---------------------------------------------------------------------------------------------------------------------------------+
     | project   person_1   person_2   person_3   person_4   d_pers~1   d_pers~2   d_pers~3   d_pers~4   gp_size   id             mbrs |
     |---------------------------------------------------------------------------------------------------------------------------------|
  1. |       1        Tom                              Tom                                         Tom         1    8              Tom |
  2. |       2       Jane                  Jane                                        Jane                    1    4             Jane |
  3. |       3        Tom       Dick                   Tom       Dick                              Tom         2    9         Dick/Tom |
  4. |       4       Jane       Dick       Jane                  Dick                  Jane                    2    5        Dick/Jane |
  5. |       5        Tom       Dick      Harry        Tom       Dick      Harry                   Tom         3   11   Dick/Harry/Tom |
     +---------------------------------------------------------------------------------------------------------------------------------+
person Richard Herron    schedule 20.10.2012
comment
Я не понимаю, как этот код обращается к перестановкам и алфавитному порядку. Кроме того, насколько я понимаю, структура данных OP отличается: person_1 всегда будет непустым, person_2 будет непустым для проектов, над которыми работали 2+ человека и т. д. - person StasK; 21.10.2012
comment
@richardh Спасибо за код, однако СтасК верен, это не отвечает на мои основные вопросы в (2) и (3), и мои данные структурированы таким образом, что человек_1 всегда непуст, и если есть имя в person_4 это означает, что это проект для 4 человек. Любые идеи по решению (2) и (3) будут полезны. - person CJ12; 21.10.2012
comment
Я не был уверен, как ваши данные были закодированы, поэтому я решил, как я буду их кодировать. С кодировкой, которую описывает @StasK, вам будет трудно решить (2) и (3). Я думаю, что вам лучше всего перекодировать ваши данные. - person Richard Herron; 21.10.2012
comment
@Stask, у тебя есть какие-нибудь мысли? Я не могу изменить способ кодирования моих данных. - person CJ12; 21.10.2012
comment
Я бы сделал это в Mata, чтобы иметь возможность сортировать по строке (чтобы создать уникальную групповую метку для ваших задач (1) и (2); задача (3), очевидно, легко решается, как в ответе Фр. ). Разработка надежного решения займет у меня некоторое время, а сейчас у меня есть рабочие приоритеты. Вы можете спросить у statalist, в то же время. - person StasK; 23.10.2012
comment
Есть ли что-то, чего не делает приведенное выше решение? Кажется, это позволяет достичь всех трех пунктов. - person Richard Herron; 23.10.2012