Нахождение лучшей точки компромисса на кривой - PullRequest
46 голосов
/ 07 января 2010

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

Я делаю выбор модели, используя тип критерия AIC / BIC / MDL , который вознаграждает модели с низкой ошибкой, но также наказывает модели с высокой сложностью (мы ищем самое простое, но наиболее убедительное объяснение этих данных, так сказать, а-ля бритва Оккама ).

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

aic-bic fit

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

Моей первой интуицией было попытаться нарисовать линию под углом 45 градусов от угла и продолжать двигаться до пересечения кривой, но это легче сказать, чем сделать :) Также она может пропустить интересующую область, если кривая немного перекос.

Есть мысли о том, как это реализовать, или лучшие идеи?

Вот образцы, необходимые для воспроизведения одного из приведенных выше сюжетов:

curve = [8.4663 8.3457 5.4507 5.3275 4.8305 4.7895 4.6889 4.6833 4.6819 4.6542 4.6501 4.6287 4.6162 4.585 4.5535 4.5134 4.474 4.4089 4.3797 4.3494 4.3268 4.3218 4.3206 4.3206 4.3203 4.2975 4.2864 4.2821 4.2544 4.2288 4.2281 4.2265 4.2226 4.2206 4.2146 4.2144 4.2114 4.1923 4.19 4.1894 4.1785 4.178 4.1694 4.1694 4.1694 4.1556 4.1498 4.1498 4.1357 4.1222 4.1222 4.1217 4.1192 4.1178 4.1139 4.1135 4.1125 4.1035 4.1025 4.1023 4.0971 4.0969 4.0915 4.0915 4.0914 4.0836 4.0804 4.0803 4.0722 4.065 4.065 4.0649 4.0644 4.0637 4.0616 4.0616 4.061 4.0572 4.0563 4.056 4.0545 4.0545 4.0522 4.0519 4.0514 4.0484 4.0467 4.0463 4.0422 4.0392 4.0388 4.0385 4.0385 4.0383 4.038 4.0379 4.0375 4.0364 4.0353 4.0344];
plot(1:100, curve)

EDIT

Я принял решение, данное Йоной . В основном, для каждой точки p на кривой мы находим точку с максимальным расстоянием d, определяемым как:

point-line-distance

Ответы [ 11 ]

0 голосов
/ 21 января 2019

Если хотите, я перевел его на R как упражнение для себя (простите за мой неоптимизированный стиль кодирования). * Применял его, чтобы найти оптимальное количество кластеров на k-средних - работал довольно хорошо.

elbow.point = function(x){
elbow.curve = c(x)
nPoints = length(elbow.curve);
allCoord = cbind(c(1:nPoints),c(elbow.curve))
# pull out first point
firstPoint = allCoord[1,]
# get vector between first and last point - this is the line
lineVec = allCoord[nPoints,] - firstPoint;
# normalize the line vector
lineVecN = lineVec / sqrt(sum(lineVec^2));
# find the distance from each point to the line:
# vector between all points and first point
vecFromFirst = lapply(c(1:nPoints), function(x){
  allCoord[x,] - firstPoint
})
vecFromFirst = do.call(rbind, vecFromFirst)
rep.row<-function(x,n){
  matrix(rep(x,each=n),nrow=n)
}
scalarProduct = matrix(nrow = nPoints, ncol = 2)
scalarProduct[,1] = vecFromFirst[,1] * rep.row(lineVecN,nPoints)[,1]
scalarProduct[,2] = vecFromFirst[,2] * rep.row(lineVecN,nPoints)[,2]
scalarProduct = as.matrix(rowSums(scalarProduct))
vecFromFirstParallel = matrix(nrow = nPoints, ncol = 2)
vecFromFirstParallel[,1] = scalarProduct * lineVecN[1]
vecFromFirstParallel[,2] = scalarProduct * lineVecN[2]
vecToLine = lapply(c(1:nPoints), function(x){
  vecFromFirst[x,] - vecFromFirstParallel[x,]
})
vecToLine = do.call(rbind, vecToLine)
# distance to line is the norm of vecToLine
distToLine = as.matrix(sqrt(rowSums(vecToLine^2)))
##
which.max(distToLine)
}

вход x функции должен быть списком / вектором с вашими значениями

...