Использование квалификатора 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/
для широкого обсуждения.
(если цифры становятся большими, работайте с double
s.)
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)
Это все хорошо для переписи фирм. Если у вас есть образец фирм, и вам нужно применить веса, я не уверен, какое хорошее решение было бы. Мы можем устроить мозговой штурм, если понадобится.