Как найти тренд (рост/уменьшение/стационарность) ряда данных

Я пытаюсь извлечь тенденцию OEE производственной машины. У меня уже есть набор данных OEE, который рассчитывается примерно каждые 30 секунд для каждой производственной машины и хранится в базе данных.

Что я хочу сделать, так это извлечь подмножество набора данных (скажем, за последние 30 минут) и указать, вырос ли OEE, уменьшился или был стабильным (в пределах определенного порога). Моя задача состоит НЕ в том, чтобы предсказать, каким будет следующее значение OEE, а просто в том, чтобы узнать, уменьшилось ли (желаемое возвращаемое значение: -1), выросло ли (желаемое возвращаемое значение: +1< /em>) или был стабильным (желаемое возвращаемое значение: 0) в зависимости от набора данных. Я использую Java 8 в своем проекте.

Вот пример набора данных:

71.37
71.37
70.91
70.30
70.30
70.42
70.42
69.77
69.77
69.29
68.92
68.92
68.61
68.61
68.91
68.91
68.50
68.71
69.27
69.26
69.89
69.85
69.98
69.93
69.39
68.97
69.03

Из этого набора данных можно заявить, что OEE уменьшалась (разумеется, на основе порогового значения), поэтому алгоритм вернет -1.

Я безуспешно искал в сети. Я нашел этот, или этот проект github, или этот вопрос stackoverflow. Однако все это (более или менее) сложный алгоритм прогнозирования. Я ищу гораздо более простое решение. Любая помощь приветствуется.


person Francesco Sgaramella    schedule 09.05.2019    source источник
comment
Что вы подразумеваете под гораздо более простым решением? Я могу придумать очень простое решение - сравнить первое и последнее значение (и посмотреть, превышает ли разница порог).   -  person Sweeper    schedule 09.05.2019
comment
Сравнение первого и последнего значения не является подходящим решением, поскольку оно не указывает тенденцию ряда данных. Например, имея набор данных, такой как: [5, 7, 8, 11, 17, 3], с вашим предложением тенденция будет указывать на то, что OEE имеет отрицательную тенденцию, в то время как явно растет тенденция, принимая во внимание весь набор данных. .   -  person Francesco Sgaramella    schedule 09.05.2019
comment
Хорошо, а как насчет поиска различий между каждой соседней парой? Для вашего примера в комментарии это будет [2, 3, 3, 6, -14]. И вы проверяете, больше ли положительных различий, чем отрицательных?   -  person Sweeper    schedule 09.05.2019
comment
Как бы вы определили тенденцию для набора данных, похожего на [5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5]?   -  person m.raynal    schedule 09.05.2019


Ответы (2)


Вы можете выбрать
скользящее среднее последних n значений.
Или
скользящее среднее последних n значений.

Это сильно зависит от вашего приложения, что подходит. Но оба они очень просты в реализации и во многих случаях более чем хороши.

person MrSmith42    schedule 09.05.2019

Как вы знаете из математики, можно было бы использовать d/dt, что более или менее использует разность шагов.

Тренд должен иметь определенный вес.

class Trend {
    int direction;
    double probability;
}

Trend trend(double[] lastData) {
    double[] deltas = Arrays.copyOf(lastData, lastData.length - 1);
    for (int i = 0; i < deltas.length; ++i) {
       deltas[i] -= lastData[i + 1];
    }
    // Trend based on two parts:
    int parts = 2;
    int splitN = (deltas.length + 1) / parts;
    int i = 0;
    int[] trends = new int[parts];
    for (int j = 0; j < parts.length; ++j) {
        int n = Math.min(splitN, parts.length - i);
        double partAvg = DoubleStream.of(deltas).skip(i).limit(n).sum() / n;
        trends[j] = tendency(partAvg);
    }
    Trend result = new Trend();
    trend.direction = trends[parts - 1];
    double avg = IntStream.of(trends).average().orElse((double)trend.direction);
    trend.probability = ((direction - avg) + 1) / 2;
    return trends[parts - 1];
}

int tendency(double sum) {
    final double EPS = 0.0001;
    return sum < -EPS ? -1 : sum > EPS ? 1 : 0;
}

Это не очень сложно. Для более подробного рассмотрения может быть полезен математический форум.

person Joop Eggen    schedule 09.05.2019
comment
Мне нужно понять, что содержит переменная sums в строке double sum = DoubleStream.of(sums).skip(i).limit(n).sum() / n; - person Francesco Sgaramella; 09.05.2019
comment
Извините, sums должно было быть deltas. Выражение вычисляет среднее значение deltas[i : i+n] - person Joop Eggen; 09.05.2019