Как создать переменные элемента из общей переменной счета - PullRequest
2 голосов
/ 10 октября 2019

Я хочу смоделировать оценку предмета из общего счета.

Например, я сгенерировал общий балл, который имеет баллы от 5 до 25. Я хотел бы распределить этот общий балл по пяти элементам, каждый из которых имеет 5 -Лайкертовский балл.

Затем я использовал цикл while для проверки состояния в Stata 15. Выполнение кода заняло слишком много времени, чтобы завершить цикл, и я не знаю, допустил ли я ошибку.

Возможно, кто-то хотел бы предложить другой способ имитации оценки предмета из общего балла?

Мой код:

set obs 200

generate id=_n
generate u_i= rnormal(0, 0.5)
generate gr = runiform()>0.5
generate sex = runiform()>0.4
generate age = round(rnormal(65, 10))

expand 5

bysort id: generate time=_n  

generate e_ij = rnormal(0, 1.0)

generate run=_n

*Generate Sum score 5-25

generate y = 3.0 + 2.0*gr + 0.2*age -1.2*sex + 0.5*time + u_i + e_ij

summarize y

replace y = round(y)

*Generate each item

forvalues k = 1(1)5 {
    generate item`k' = runiform(1, 5)
    replace item`k' = round(item`k')
}

egen sum_item=rowtotal(item1 item2 item3 item4 item5)       
generate diff = y - sum_item


*Looping check if y=sum_item    

forvalues a = 1(1)`=_N'  {
    quietly gsort -diff
    while sum_item!=y[`a'] {
        replace sum_item=. if sum_item!=y[_n]

        forvalues k = 1(1)5 {   
           replace item`k' =. if sum_item==.

           replace item`k' = runiform(1, 5) if item`k'==.
           replace item`k' = round(item`k') 
                        }
           replace sum_item= item1 + item2+item3+item4+item5 if sum_item==.
           replace diff = y - sum_item  
           if (sum_item==y[`a']) continue, break
        }
    }

Ожидаемые данные, которые я хотел бы получить:

The expected data which I would like to have

Как видите, после выполнения цикла я всегда будуполучить 2 - 4 случаев, когда программа продолжает работать, генерируя оценку предмета (item1 - item5), пока переменная diff не станет равной нулю.

1 Ответ

0 голосов
/ 12 октября 2019

Если я правильно понимаю, вы можете зациклить что-то вроде следующего (после установки всех элементов в начальные значения 1, так как возможные значения от 1 до 5):

capture generate rand_int = 0
replace rand_int = floor( 5 * runiform() + 1 )  // random int, 1 to 5
capture generate cnd = 0

forvalues k = 1(1)5 {
    replace cnd = rand_int == `k' & sum_item < y & item`k' < 6
    replace item`k' = item`k' + 1 if cnd
}

replace sum_item = item1+item2+item3+item4+item5

В словах,это говорит о том, что если sum_item < y, то случайным образом добавить 1 к одному из элементов (при условии, что этот элемент еще не равен 5), и тогда вы продолжите делать это до sum_item == y для всех строк.

Так что это будет сходиться примерно за 20 итераций, если максимальное значение y равно 25, а элементы от 1 до 5. Я говорю «примерно», потому что здесь есть небольшая трата, когда вы добавляете 1 к элементуэто уже равно 5. Вы могли бы добавить дополнительный код для этого, но я бы не стал беспокоиться, если это достаточно быстро. Например, для высоких значений item_sum было бы более эффективно начинать с начальных значений 5 и случайным образом вычитать 1, пока оно не сходится.

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

...