В этой статье мы прольем свет на секретное оружие Статы: Мата. Хотя большинство людей слышали об этом, а некоторые, возможно, даже баловались командами Mata, очень немногие рискнули глубоко проникнуть на его территорию, чтобы исследовать то, что на самом деле лежит за пределами очевидных приложений некоторой матричной алгебры.

Фактически, Мата - это очень отдельный мир от Статы, функционирующий со своим собственным набором правил и процедур. На сегодняшний день на этом языке написано всего две книги. Один принадлежит Уильяму Гулду, президенту StataCorp, а второй - старшему разработчику Кристоферу (Кит) Бауму, который также является привратником программ Stata. Обе книги связаны в конце этой статьи. Помимо этих двух книг и некоторых сообщений в блогах на веб-сайте Stata, существует очень немногое о систематическом введении в различные аспекты этого языка.

В то время как Stata достаточно для повседневного использования и достаточно умен, чтобы понимать общие команды, Mata, язык низкого уровня, быстрее и гибче, чем Stata, но это не так снисходительно. Это требует точности и дисциплины. Точность, потому что она имеет дело с матрицами, где согласованность имеет значение, а синтаксис должен быть на 100% правильным. И дисциплина, потому что существует небольшая поддержка и база знаний. Помимо некоторых обсуждений на форумах Stata, которые действительно дают некоторые советы и подсказки, для выяснения ситуации в основном используются файлы справки Mata.

Так зачем нам изучать Мата? Чтобы ответить на этот вопрос, нам нужно знать, на что все это способно. Для этого требуется выйти за рамки стандартных операций Stata / Mata, когда данные передаются туда и обратно, и действительно понять все возможные инструменты, которые предоставляет Mata. Это означает, что нужно погружаться так глубоко в ландшафт Мата, что Статы не видно. Хотя синтаксис этих двух языков частично совпадает, Mata в значительной степени является отдельным языком. Mata также является предпочтительным оружием разработчиков верхнего уровня для создания программ Stata, особенно там, где требуется множество нелинейных, сложных процедур оптимизации. Большинство операций Mata также похожи на R / MATLAB, особенно когда речь идет о матричной алгебре. Он также имеет свой собственный набор встроенных решателей, которые, например, включают оптимизированные операции для умножения матриц, обращения матриц, разложения матриц и т. Д. Он также включает собственный набор программ для решения более сложных задач, таких как оптимизация и линейная алгебра. , о которых мы также поговорим в этом руководстве.

Это руководство не предназначено для ознакомления с Мата или матрицами, по которым можно найти множество вводных материалов в Интернете. Но он предназначен для демонстрации инструментов с некоторыми базовыми приложениями. Это руководство также не охватывает все аспекты Mata, потому что (а) их слишком много, (б) некоторые инструменты, которые мне все еще нужно выяснить самим, и (в) некоторые вещи, которые я, вероятно, не буду использовать сам. , например массивы. Некоторые из них могут быть добавлены позже в это руководство.

Чтобы дополнить материал этого руководства, также выпущен плакат размера A0, который вы также можете распечатать и повесить для быстрого доступа:

Путеводитель представляет Мата в пяти частях:

  • Часть I: начало работы
  • Часть II: матрицы (в пяти частях)
  • Часть III: от Статы к Мате
  • Часть IV: оптимизация
  • Часть V: линейное программирование

Итак, приступим.

Часть I. Начало работы

Чтобы использовать Mata, нам нужно инициализировать его как экземпляр. Это можно сделать двумя способами. Либо мы пишем блок кода Mata:

mata
< mata command 1 >
< mata command 2 >
< and so on >
  
end

или мы используем единственный экземпляр:

mata <a mata command>

Блок кода - это более стандартный способ использования Mata, поскольку он позволяет выполнять множество операций. Однострочное использование Mata в программах действительно существует, но это более редкий случай. Из личного опыта, однострочные экземпляры Mata в основном используются для проверки некоторых вычислений или просто для просмотра переменных Mata.

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

mata:
<stuff here>
end
mata: <command here>

Если используется двоеточие и возникает ошибка, то экземпляр Mata прерывается, один возвращается в Stata, и появляется сообщение об ошибке. Программы, написанные на Mata, скорее всего, будут использовать mata: <command>, чтобы остановить выполнение кода, если произойдет какая-то ошибка (это должно произойти) и появится сообщение об ошибке. В противном случае интерактивная версия Mata без двоеточия (mata <command>), продолжает работать, даже если возникает ошибка, и завершается только при обнаружении end для завершения экземпляра Mata.

Как и Stata, Mata также имеет свой набор команд, используемых для проверки переменных, хранящихся в памяти. Вот некоторые из наиболее распространенных, которые следует запомнить:

mata describe              // describe all variables
mata clear                 // clear all variables    
mata rename <name>         // rename a variable
mata drop <names>          // drop variables
mata set                   // set Mata parameters  
mata stata                 // Execute a Stata command  

Также можно использовать две косые черты // для комментариев в Mata. Обратите внимание, что, в отличие от Stata, звездочки * не работают в Mata.

Все, что сгенерировано в Mata, остается в памяти, если Stata не закрыта или все не очищено clear all или mata: mata clear. Дополнительные параметры см. В help mata_set, и это тоже очень рекомендуется. Например, один из часто обсуждаемых вариантов - это set matastrict on, который явно требует, чтобы матрицы были объявлены и определены перед использованием в программах.

Часть II: Матрицы

Информация в Mata может храниться в виде матричных переменных или программ и функций. Сами матричные переменные могут быть скалярами (отдельные числа), векторами (отдельные строки или столбцы) или матрицами (n строк умноженные на m столбцов). Mata достаточно умен, чтобы определить, какая переменная является матричным типом, но иногда это также нужно контролировать (опять же matastrict здесь полезен).

Часть II.1: Определение матриц

Матрицы можно создавать разными способами. Одним из наиболее распространенных способов использования является импорт данных Stata в виде матрицы Mata:

mata: X = st_data(.,("var1", "var2"))

где мы определяем матрицу X, которая имеет все наблюдения (или строки), а столбцы - это var1 и var2. Это довольно распространенный вариант, особенно если у вас уже есть набор данных, с которым можно поиграть. Команды st_ позволяют Mata взаимодействовать со Stata для передачи информации туда и обратно. См. help m4_stata для получения более подробной информации.

Кроме того, здесь я хотел бы также отметить, что команда st_view похожа на st_data, но физически изменяет набор данных Stata. Короче говоря, st_view более эффективен с точки зрения памяти, чем st_data (поскольку данные не нужно загружать), но более опасен, поскольку он изменяет «сырые» данные. Любой из них может использоваться в зависимости от приложения. См. help mf_st_view для получения более подробной информации.

Другой вариант - определить матрицы внутри Mata. Это можно сделать, просто введя матрицу вручную:

mata A = (1,2\3,4)

Матрицу A можно просмотреть, набрав mata A, что в основном показывает квадратную матрицу 2x2 на дисплее:

1 2
3 4

Обратите внимание, что запятая , используется для разделения элементов строки, а обратная косая черта \ используется для перехода к следующей строке. Элементы должны соответствовать строкам и столбцам, иначе Mata выдаст ошибку. Использование скобок также необязательно в Mata, но в основном это делается для удобства пользователя, так как это упрощает чтение кода. Комбинации запятых , и косых черт \ также могут использоваться для определения векторов. Например:

mata 1,2,3
mata 1\2\3

являются векторами-строками и столбцами соответственно.

Также можно определить специальные матрицы. Например:

mata 1..4
mata 1::4

- это векторы строк и столбцов от 1 до 4. Также можно использовать специальные функции, например:

mata J(2,2,1)

чтобы сгенерировать матрицу единиц 2 на 2. Поскольку матрица ix симметрична, Mata будет показывать только нижний треугольник, но только для отображения. Общая форма этой команды mata J(rows, cols, constant value) может генерировать матрицу любого измерения и заполнять ее постоянным значением.

Матрицы идентичности строк и столбцов n определяются как:

mata I(5)

или единичные векторы как:

mata e(2,5)

где длина вектора равна 5 и где все элементы равны нулю, кроме второго элемента, который равен единице. Итак, этот вектор будет выглядеть как (0,1,0,0,0).

Другая встроенная векторная операция включает в себя:

mata range(1,7,2)

который создает вектор, который начинается с 1 и заканчивается 7 с шагом два. Или (1,3,5,7).

Также можно использовать множество встроенных функций распределения для генерации случайных матриц. Например, матрица случайных значений, взятых из равномерного диапазона 0,1:

mata runiform(3,3)

который создаст матрицу 3x3. См. help mf_runiform для меню всех встроенных дистрибутивов.

Часть II.2: Доступ к матричным элементам

Доступ к матричным элементам также можно получить несколькими способами. Давайте определим случайно сгенерированную матрицу:

mata A = runiform(3,3)

Мы можем получить доступ к отдельным значениям в матрице. Например:

mata A[1,2]  // row 1, col 2
mata A[3,3]  // row 3, col 3

- это отдельные элементы, определяемые индексами строк и столбцов соответственно. Также можно получить доступ к целым столбцам и строкам:

mata A[1,.]   // row 1
mata A[.,2]   // col 2

или извлеките подмножество матрицы:

mata A[|2,1\3,3|]       // start from row2,col1 to row3,col3
mata A[(2::3),(1..3)]   // select rows 2 to 3, and cols 1 to 3

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

Также существуют различные другие варианты, например, извлечение диагональных элементов квадратных матриц:

mata diag(A)
mata diagonal(A)

Две приведенные выше команды разные! Проверь их :)

Матрицы также можно добавлять друг к другу. Например,

mata
A = runiform(1,2)
B = runiform(1,2)
A,B   // join the columns (rows must be the same)
A\B   // stack A on top of B (columns be the same)
end

где первая опция A,B просто добавляет матрицу B перед матрицей A, а A\B стек A поверх B. Обе эти опции часто используются, особенно при итеративном генерировании матриц через циклы. Например, их можно использовать для «сбора» оценок из регрессий в единую матрицу.

Часть II.3: Матричные операции

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

Матричные операции, например, умножение A*B означает, что строки A должны равняться столбцам B. В Mata эти стандартные операции довольно просты:

mata
 A = (1,2,3\4,5,6)
 B = (2,3\4,5\6,7)
 A * B
end

Но для поэлементных операций каждый (n, m) элемент A умножается на (n, m) элемент B. Другими словами, в приведенном выше примере A:*B не будет работать, потому что элементы не выровнены. A - это (2,3), а B - (3,2). Один из них необходимо переставить. Это можно сделать следующим образом:

mata
 A = (1,2,3\4,5,6)
 B = (2,3\4,5\6,7)
  A' :* B
  A  :* B'
end

Здесь первый пример поэлементного умножения A' * B дает матрицу 3x2, а второй пример A * B' дает матрицу 2x3. Независимо от того, выполняется ли матричное умножение или поэлементное умножение, размеры должны соответствовать этой конкретной операции. В Mata существует несколько других элементов матричной алгебры, например A+B против A:+B или A/B против A:/B. Для получения дополнительных сведений см. help m2_op_colon.

Матрицы также могут иметь логические операторы, например A==B проверяет условие, если обе матрицы равны. Такие условия можно использовать в некоторых циклах if / else / while. Можно также проверить поэлементные условия A:==B, которые проверяют, все ли отдельные элементы A равны отдельным элементам B. Поскольку это своего рода редкое требование, более распространенным приложением будет A:>=B, или A является поэлементным. больше или равно B.

Mata также допускает поэлементные операции как часть скалярных функций (см. help m4_scalar). Вот некоторые примеры:

mata
  X = (-2, 1 \ 0, 5)
  abs(X)   // absolute value of each element
  sign(X)  // sign of each element: negative -1, positive 1
  exp(X)   // exponential
  sqrt(X)  // square root
  sin(X)   // sin
end

У каждой из этих операций есть множество других опций. Например, exp() также можно заменить на log() или ln(). Аналогично, cos(), tan() и т. Д. Также являются вариантами. Они также перечислены на плакате, ссылка на который приведена выше. Также проверьте справку каждого из них для получения более подробной информации.

Часть II.4: Матричные функции Мата

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

mata
A = (5,4\6,7)
B = (1,6\3,2)
end

Двумя наиболее часто используемыми матричными функциями являются:

mata rows(A)
mata cols(A)

или количество строк и столбцов матрицы.

Другие операции включают:

mata rowsum(B)
mata colsum(B)

Как следует из названий, это суммы строк и столбцов соответственно. Другие параметры включают rowmin, rowmax, runsum и т. Д. Подробнее см. help m4_mathematical.

Более необычная функция - mean(). Среднее дает только средние значения столбцов и возвращает вектор-строку. Для суммирования строк можно использовать двойное транспонирование:

mata mean(B')'

Mata также позволяет более расширенный выбор матриц:

mata D = (1,0,2,3,0)
mata selectindex(D) // select all the non-zero columns

где select index возвращает только ненулевые значения, которые в данном случае будут (1,2,3).

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

select(B, B[.,1]:>2)

Здесь вы можете увидеть, что указано несколько параметров. Здесь select можно использовать для генерации условных матриц, где условия могут быть определены для любой другой матрицы, имеющей такие же размеры. Например, мы можем выбрать строки A, исходя из условия, что элементы B положительны. См. help mf_select для получения более подробной информации.

Mata также позволяет сортировать матрицы. Например, попробуйте:

mata sort(B,2)  
mata jumble(B) 

где первая опция сортирует по второму столбцу B, а вторая опция рандомизирует строки B. См. help mf_sort для дополнительных опций.

Mata имеет несколько встроенных решателей для манипулирования матрицами или извлечения их свойств. Некоторые из них перечислены здесь:

mata
A = (5,4\6,7)
det(A)         // determinant of A
invsym(A)      // inverse of A
trace(A)       // trace of A
rank(A)        // rank of A
norm(A)        // norm of A
X=.            // eigen vectors
L=.            // eigen values
eigensystem(A,X,L)  // eigen system of A
cholesky(A)    // Cholesky decomposition of A
end

Некоторые команды также работают с двумя матрицами, например:

mata
A = (5,4\6,7)
B = (1,6\3,2)
A' * B            // A x B
cross(A,B)        // A x B using a solver (faster)
quadcross(A,B)    // cross with quad precision (more accurate)
lusolve(A,B)      // Given Ax=B, solve for x using LU decomposition
qrsolve(A,B)      // Given Ax=B, solve for x using QR decomposition
end

Есть множество других вариантов, но все это зависит от контекста. Полный список команд см. В help m4_matrix.

Часть II.5: Циклы с использованием операторов for, while и if / else

При программировании также часто используются циклы и условия if / else или while. Они следуют той же логике, что и в Stata, и здесь кратко описаны.

Цикл while определяется следующим образом:

mata
  x = 1                  // starting value
  X = 4                  // ending value
  while (x <= X) {       // start while condition   
  printf("%g \n", x)     // some Mata operation here
  x++                    // increment x by 1
  }                      // end while loop
end

Здесь мы говорим Mata продолжать цикл до тех пор, пока x не станет равным 4. Для цикла while обратите внимание на использование скобок, где указаны условия.

Циклы for определены следующим образом:

mata
   N = 4                      // ending value
   for (i=1; i<=N; i++) {     // for loop 
   printf("%g \n", i)         // some Mata operation here
   }                          // end for loop
end

Здесь также обратите внимание на использование оператора for. Это сильно отличается от Stata и должно быть указано именно в этом формате. Начальные и конечные значения могут быть извлечены из некоторых условных операторов, таких как размеры матриц. Но в идеале определяйте их вне цикла for как отдельные переменные. Кроме того, в отличие от Stata, Mata допускает приращение только на 1.

Условия if / else указаны следующим образом:

mata
 x = 3                       // value of x
   
  for (i=1; i<=5; i++) {     // start some for loop
    if (x > i) {             // if condition
      printf("%g\n", 0)      // Mata commands if if condition holds
      }
    else {                   // otherwise
      printf("%g\n", 1)      // run these Mata commands
      }
  }
end

Здесь логика проста, но также важно убедиться, что синтаксис указан правильно. Еще несколько замечаний, цикл for для if / else не нужен. Это просто для демонстрации того, как это можно использовать в цикле. То, что мы делаем выше, говорит Mata вернуть 0, если i<=3 и 1, иначе, поскольку i повторяется от 1 до 5.

Можно также указать сколько угодно условий, используя if, else if, else if,…, else. Можно также вложить любую комбинацию условий if / else, for, while друг в друга. Это просто вопрос отслеживания того, что делает каждый шаг. В общем, эти операторы должны быть полностью полными, в том смысле, что они должны охватывать все элементы и все возможные условия, с которыми можно столкнуться, иначе код может сломаться.

Если есть два условия, Mata также допускает использование оператора if / else в C ++:

(a ? b : c)

где a ? - логическое условие "истина / ложь", b - значение, если утверждение истинно, и c, если оно ложно. В приведенном выше примере это будет иметь вид:

(x > i ? 1 : 0)

Условия if / else могут также принимать более сложные функциональные формы. См., Например, viewsource diag.mata, где используется множество вложенных условий if / else.

Часть III: Стата к Мате

Одно из наиболее распространенных применений Mata - использование данных из Stata для выполнения некоторого регрессионного анализа с использованием матричной алгебры. Вот стандартный пример - выполнить простой OLS в Mata. Поскольку каждый в конце концов узнает, что beta = (X’X)^(-1) X’y, это, вероятно, самый простой способ применить.

Полный блок кода приведен ниже:

sysuse auto, clear
mata
 y = st_data(.,"price")
 X = st_data(.,("mpg", "weight"))
 X = X, J(rows(X),1,1)
    beta   = invsym(cross(X,X))*cross(X,y)
    esq    = (y - X*beta) :^ 2
    V      = (sum(esq)/(rows(X)-cols(X)))*invsym(cross(X,X))
    stderr = sqrt(diagonal(V))
      st_matrix("b", beta)
      st_matrix("se", stderr)
end

Сначала мы загружаем автоматический набор данных. В Mata зависимая переменная импортируется как вектор y. независимые переменные импортируются как матрица X. К этой матрице X добавляется вектор-столбец единиц для точки пересечения. Поскольку Stata показывает точку пересечения в конце таблиц регрессии, вектор единиц добавляется в конец X, но это также может быть добавлено в начале. Поскольку вектор единиц должен иметь такое же количество строк, что и матрица X, обратите внимание на использование оператора J().

Как только данные будут получены, следующим шагом будут вычисления. Бета-коэффициенты рассчитываются как (X'X)^-1 *(X'y). Обратите внимание на использование решателей Mata invsym и cross. Точно так же квадрат ошибки каждого элемента вычисляется как e_i^2=(y_i — b x_i)^2, где каждый элемент i возведен в квадрат и, следовательно, здесь используется :^2. Ковариационная матрица дисперсии вычисляется по формуле V=(X'X)^(-1) * sum_i(e_i^2)/n-k, а стандартные ошибки - это квадратный корень из диагональных элементов (дисперсии) матрицы V. Обратите внимание, что мы используем diagonal, а не diag. На последнем этапе бета-версии и стандартные ошибки экспортируются в Stata в виде матриц Stata.

Давайте сравним все это:

// Mata variables stored in memory
mata: beta
mata: stderr
// Stata matrices exported from Mata
mat li b
mat li se
// Stata regression
regress price mpg weight

Все они должны давать одинаковые коэффициенты и стандартные ошибки. На основе этих принципов можно воспроизвести любой тип регрессии. Другая часть, которую я не буду рассматривать, - это то, как писать программы на Mata, которые можно использовать как функции Stata с возвращаемыми переменными e-class и r-class. Для этого требуются руководства сами по себе, и, вероятно, не все будут использовать их. Для начала взгляните на этот пост в официальном блоге Stata. Если вы относитесь к этому еще серьезнее, взгляните на книги Мата, размещенные в конце этого руководства.

Часть IV: Оптимизация

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

Вместо того, чтобы обсуждать более сложные приложения оптимизации с некоторыми сложными функциями и оценками правдоподобия, здесь дается более мягкое введение. Мы начнем с определения простой кубической функции с функциональной формой y = -4x^3 +3x^2 + 25x + 6.

Его можно построить в Stata следующим образом:

twoway (function -4*x^3 + 3*x^2 + 25*x + 6, range(-4 4)), ///
 yline(0) xline(0) aspect(1) xsize(1) ysize(1) xlabel(-4(1)4)

который рисует фигуру, которую мы видим слева. Здесь мы видим, что у этой функции есть две поворотные точки. Точка максимума между значениями 1 и 2 на оси x и точка минимума между значениями -2 и -1.

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

help mf_optimize

Для оптимизации в Mata необходимо определить функцию оптимизации. Обычно это принимает следующие формы:

mata
 void myfunc(todo, x, y, g, H) {
    y = -4*x^3 + 3*x^2 + 25*x + 6
    }
end

Здесь todo - общее название типа функции оценщика оптимизации, которая принимает три значения: 0, 1 и 2. Параметр по умолчанию 0 сохраняет информацию о минимальном на максимальном значении, 1 сохраняет 0 плюс значение градиента (первая производная) в g, а 2 сохраняет 0 плюс 1 плюс гессианское значение (вторая производная) в H. Это требует более подробного обсуждения, но для этого примера мы будем использовать вариант по умолчанию. См. Файлы справки для объяснения, если вы хотите узнать больше.

Здесь x и y - переменные функции, которые необходимо вычислить. Эти варианты имеют больше смысла для более сложных примеров. На следующем этапе мы определяем оценщики оптимизации следующим образом:

mata
   void myfunc(todo, x, y, g, H) {
      y = -4*x^3 + 3*x^2 + 25*x + 6
      }
maxval = optimize_init()
optimize_init_which(maxval, "max")
optimize_init_evaluator(maxval, &myfunc())
optimize_init_params(maxval, 1)
xmax = optimize(maxval)
xmax
end

Давайте по очереди обсудим команды оптимизации. Первая строка инициализирует экземпляр optimize и вызывает его maxval. Во второй строке говорится, что мы хотим максимизировать, используя параметр «max». Эта строка технически не нужна, так как по умолчанию используется максимизация. Затем мы определяем функцию, которую хотим максимизировать. Четвертая строка говорит, с чего начать поиск. Здесь мы указываем значение 1. В этом нет необходимости, поскольку эта функция довольно плавная, поэтому подойдет любое начальное значение. Но эти параметры инициализации играют важную роль при работе со сложными функциями с локальными максимумами или минимумами или нелинейными функциональными формами. Пятая строка говорит, что мы сохраняем максимальное значение в скаляре Mata xmax. Последняя строка в основном отображает это значение. Для нашей кубической функции это оценивается как 1,715.

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

mata
  void myfunc(todo, x, y, g, H) {
   y = -4*x^3 + 3*x^2 + 25*x + 6
  }
    // maximum point
    maxval = optimize_init()
    optimize_init_which(maxval, "max")
    optimize_init_evaluator(maxval, &myfunc())
    optimize_init_params(maxval, 1)
       xmax = optimize(maxval)
    
    // minimum point
    minval = optimize_init()
    optimize_init_which(minval, "min")
    optimize_init_evaluator(minval, &myfunc())
    optimize_init_params(minval, -1)
       xmin = optimize(minval)
       xmin, xmax  // display the values
       // pass the values back to Stata
       st_local("minx", strofreal(xmin))
       st_local("maxx", strofreal(xmax))
end
twoway (function -4*x^3 + 3*x^2 + 25*x + 6, range(-4 4)), ///
 yline(0) xline(0) ///
 xline(`minx', lc(red)) xline(`maxx', lc(blue)) aspect(1) xsize(1) ysize(1) xlabel(-4(1)4)

Минимальное значение равно -1,215. Здесь мы используем параметр st_local, который преобразует значение Mata в локальное значение Stata. Для получения дополнительных сведений о функциях, связанных с интерфейсом Stata to Mata, см. help m4_stata. Приведенный выше код необходимо запустить за один раз, поскольку он имеет дело с локальными пользователями в Stata для генерации этой цифры:

где минимальная и максимальная точки поворота отмечены красной и синей линиями соответственно.

Оптимизация имеет множество приложений в эконометрике, хотя это может быть не очевидно из заранее определенных команд, которые используются. Каждый раз, когда вы видите, как какая-то функция логарифмического правдоподобия прокручивается до схождения, происходит некоторая оптимизация с использованием численных решений. Здесь можно использовать множество вещей, но более продвинутые приложения требуют отдельного руководства. Взгляните на это вводное руководство в блоге Stata.

Часть V: Линейное программирование

Линейное программирование (LP), вероятно, наименее известная или даже наименее используемая функция в Mata. Вы знали, что он вообще существует? Но это основа некоторых процедур вроде квантильных регрессий или решения симплексных задач. LP занимаются проблемами оптимизации линейных отношений. Поскольку цель и ограничения линейны, решения могут иметь как внутренние, так и угловые решения. Линейные программы обычно имеют форму, в которой некоторая целевая функция c'x максимизируется или минимизируется с учетом ограничений Ax <= b и границ u <= x <= v. Здесь x - вектор переменных, где A,b,c - известные векторы параметров, а u,v - верхние или нижние пределы для x. Обычно x≥0 является довольно часто используемым пределом (например, цены всегда должны быть положительными).

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

minimize 4x + 5y + 6z
subject to:
z - x - y  = 0
x + y     >= 11
x - y     <= 5
7x + 12y  >= 35
and:
x,y,z >=  0 

Эта проблема имеет как ограничение-равенство, так и ограничение-неравенство. Кроме того, несмотря на то, что в этой задаче указаны три x,y,z переменных, z фактически является избыточной переменной, поскольку это линейная комбинация x,y в соответствии с первым ограничением. Последняя строка определяет границы и говорит, что все переменные должны быть положительными.

В Mata все это нужно указывать отдельно. Кроме того, поскольку Mata принимает ограничения только в форме Ax<=b, ограничения >= должны быть перевернуты, чтобы соответствовать требованиям программирования. В структуре Mata LP также проводится различие между ограничениями равенства и неравенства. Таким образом, описанная выше проблема LP переписывается в структуре Mata следующим образом:

minimize:
(4,5,6)[x,y,z]
subject to equality constraints:
(-1,-1,0)[x,y,z] = 0
subject to inequality constraints:
(-1,-1,0 \ 1,-1,0 \ -7,-12,0)[x,y,z]=(-11 \ 5 \ -35)
and:
[x,y,z]>=(0,0,0)

Здесь x,y,z просто фальшивые заполнители, чтобы показать, что все должно располагаться в том же порядке, что и x,y,z. Это требует некоторой перестановки переменных в приведенных выше уравнениях.

В Мата они записываются как:

mata
// Objective function
func = (4, 5, 6)
// Equality constraints (LHS, RHS)
Leq = (-1, -1, 1)
Req = 0
// Inequality constraints (LHS, RHS)
Lineq = (-1, -1, 0 \ 1, -1, 0 \ -7, -12, 0)
Rineq = (-11 \ 5 \ -35)
// Variable bounds (LOWER, UPPER)
Lbound = (0, 0, 0)
Ubound = (., ., .)
// Initiate linear programming
q = LinearProgram()
q.setMaxOrMin("min")
q.setCoefficients(func)
q.setEquality(Leq, Req)
q.setInequality(Lineq, Rineq)
q.setBounds(Lbound, Ubound)
q.optimize()
q.parameters()
end

Здесь первая часть определяет матрицы, которые загружаются в экземпляр LinearProgram. Вторая часть LP объясняется построчно. Первая строка устанавливает q как экземпляр LP, который мы хотим оценить. Как и в случае с Оптимизацией, может существовать несколько экземпляров. Во второй строке мы используем опцию «min», чтобы сказать, что мы минимизируем. Развернуть - параметр по умолчанию. Функция func определяет последовательность коэффициентов (x,y,z). Так что все должно соответствовать этому порядку. Следующие три строки добавляют равенство, неравенство и границы в терминах матриц левой и правой частей.

Последние две строки вычисляют оптимальное значение целевой функции и отображают значения параметров. Если все работает хорошо, это должно дать x=8,y=3,z=11, где оптимальное значение целевой функции равно 113. Мы также можем визуализировать это в Stata, используя следующий код:

set obs 1
gen x = 8
gen y = 3
twoway ///
 (function y = 11 - x, range(0 11)) ///
 (function y = x - 5,  range(5 12)) ///
 (function y = (35 - 7 * x) / 12, range(0 5)) ///
 (function y = (-10 * x + 113) / 11, range(0 11) lpattern(dash)) ///
 (scatter b a, mcolor(black)), ///
  ytitle(b) yscale(noline) ylabel(0(2)12) ///
  xtitle(a) xscale(noline) xlabel(0(2)12) ///
  legend(order(1 "x + y = 11" 2 "x - y = 5" 3 "7x + 12y = 35" 4 "4x + 5y + 6z = 113") region(fcolor(none)) position(1) ring(0)) ///
  plotregion(ilcolor(black)) xsize(1) ysize(1)

что дает нам эту цифру:

Начиная с z = x + y, целевая функция сокращается до 10x + 11y, что также позволяет нам визуализировать всю проблему в двух измерениях. Из-за ограничений неравенства допустимая область находится над синей и оранжевой линиями на рисунке выше, где минимум происходит на их пересечении с x=8, y=3, решение также предоставлено с использованием решателя LP, описанного выше. Целевая функция проходит через эту точку, где находится минимальное значение 10x + 11y = 113.

И это все, что касается гида Мата! Надеюсь, вы нашли этот контент полезным. По-прежнему отсутствует множество вещей, связанных с Mata, включая комплексные числа, дату / время, строковые функции, интеграцию, локальные / глобальные переменные, работу с эффективностью памяти, более сложные матричные операции, включая массивы, и написание программ. Для некоторых из них требуется довольно сложное приложение или конкретные варианты использования. Я мог бы обновить это руководство по мере необходимости, если я чувствую, что здесь также следует обсудить некоторые другие аспекты Mata.

Если вы хотите узнать больше, я настоятельно рекомендую эти две книги Mata:



и более продвинутый:



Помимо этих двух книг, в грядущем издании Камерона и Триведи 2021 года каноническая книга по эконометрике, кажется, охватывает довольно много вещей о Мате с некоторыми практическими применениями. Как только он будет выпущен, я также опубликую об этом здесь.

Об авторе

Я экономист по профессии и использую Stata с 2003 года. В настоящее время я живу в Вене, Австрия, где я работаю в Венском университете экономики и бизнеса (WU) и в Международном институте прикладного системного анализа ( МИПСА) . Вы можете найти мою исследовательскую работу в ResearchGate и Google Scholar, а также в различных репозиториях на GitHub. Я также регулярно размещаю материалы Stata в Твиттере. Вы можете связаться со мной через Medium, Twitter, LinkedIn или просто по электронной почте: [email protected].

The Stata Guide регулярно выпускает потрясающий новый контент. Хлопайте и / или следуйте, если вам нравятся эти руководства!