Использование квалификатора if с egen в Stata

Я использую Stata, и я пытаюсь вычислить среднюю цену конкурентов фирм на рынке. У меня есть данные, которые выглядят так:

Market    Firm   Price
----------------------
1         1      100
1         2      150
1         3      125
2         1      50
2         2      100
2         3      75
3         1      100
3         2      200
3         3      200

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

Market    Firm   Price    AvRivalPrice
------------------------------------
1         1      100      137.2
1         2      150      112.5
1         3      125      125
2         1      50       87.5
2         2      100      62.5
2         3      75       75
3         1      100      200
3         2      200      150
3         3      200      150

чтобы сделать среднее по группе, я мог бы использовать команду egen:

egen AvPrice = mean(price), by(Market)

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

3 ответов


Это способ избежать явных циклов, хотя для этого требуется несколько строк кода:

by Market: egen Total = total(Price)
replace Total = Total - Price
by Market: gen AvRivalPrice = Total / (_N-1)
drop Total

это старая нить все еще представляет интерес, поэтому материалы и методы, упущенные в первый раз, все еще применяются.

более общая техника заключается в работе с итогами. В простейшем случае, total of others = total of all-это значение. В egen рамки, которые будут выглядеть как

egen total = total(price), by(market) 
egen n = total(!missing(price)), by(market) 
gen avprice = (total - cond(missing(price), 0, price)) / cond(missing(price), n, n - 1) 

на total() функции egen игнорирует отсутствующие значения в аргументе. Если есть отсутствующие значения, мы не хотим включать их в счетчик, но мы можем использовать !missing() что дает 1, если не отсутствует, и 0, если отсутствует. egen ' s count() это еще один способ сделать это.

код, приведенный ранее, дает неправильный ответ, если пропуски присутствуют, поскольку они включены в count _N.

даже если значение отсутствует, среднее значение других значений по-прежнему имеет смысл.

если значение не отсутствует, последняя строка выше упрощает до

gen avprice = (total - price) / (n - 1) 

до сих пор, это, возможно, выглядит не более чем маленький вариант предыдущего кода, но он легко распространяется на использование весов. Предположительно, мы хотим средневзвешенное значение цен других, учитывая некоторые weight. Мы можем использовать тот факт, что total() работает с выражениями, которые могут быть более сложными, чем просто имена переменных. Действительно, приведенный выше код уже сделал это, но его часто упускают из виду.

egen wttotal = total(weight * price), by(market) 
egen sumwt = total(weight), by(market) 
gen avprice = (wttotal - price * weight) / (sumwt - weight) 

как и раньше, если price или weight не хватает, нужен более сложный код, или просто для того, чтобы исключить такие наблюдения из расчетов.

см. также FAQ stata

как создать переменные, суммируя для каждого отдельного свойства других членов группы?

http://www.stata.com/support/faqs/data-management/creating-variables-recording-properties/

для широкого обсуждения.

(если цифры становятся большими, работайте с doubles.)

EDIT 2 марта 2018, который был новый пост в старом потоке, который, в свою очередь, нуждается в обновлении. rangestat (SSC) можно использовать здесь и дает однострочные решения. Неудивительно, что вариант excludeself было явно добавлено для таких проблем. Но в то время как решение для средств легко использовать identity

mean for others = (total-value for self) / (count - 1)

многие другие сводные меры не поддаются подобному, простому трюку и в этом смысле rangestat включает в себя гораздо более общее кодирование.

clear
input Market    Firm   Price
1         1      100
1         2      150
1         3      125
2         1      50
2         2      100
2         3      75
3         1      100
3         2      200
3         3      200
end 

rangestat (mean) Price, interval(Firm . .) by(Market) excludeself 

list, sepby(Market) 

     +----------------------------------+
     | Market   Firm   Price   Price_~n |
     |----------------------------------|
  1. |      1      1     100      137.5 |
  2. |      1      2     150      112.5 |
  3. |      1      3     125        125 |
     |----------------------------------|
  4. |      2      1      50       87.5 |
  5. |      2      2     100       62.5 |
  6. |      2      3      75         75 |
     |----------------------------------|
  7. |      3      1     100        200 |
  8. |      3      2     200        150 |
  9. |      3      3     200        150 |
     +----------------------------------+

вот более короткое решение с меньшим количеством строк, которое сочетает в себе вашу оригинальную мысль и решение @onestop:

      egen AvPrice = mean(price), by(Market)
      bysort Market: replace AvPrice = (AvPrice*_N - price)/(_N-1)

Это все хорошо для переписи фирм. Если у вас есть образец фирм, и вам нужно применить веса, я не уверен, какое хорошее решение было бы. Мы можем устроить мозговой штурм, если понадобится.