Как найти тренд (рост / уменьшение / стационарность) ряда данных - PullRequest
0 голосов
/ 09 мая 2019

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

То, что я хочу сделать, - это извлечь подмножество набора данных (скажем, за последние 30 минут) и указать, выросла ли OEE, уменьшилась или была стабильной (в пределах определенного порога).Моя задача - не прогнозировать, какое будет следующее значение OEE, а просто знать, уменьшилось ли ( желаемое возвращаемое значение: -1 ), выросло ( желаемое возвращаемое значение: + 1 ) или был стабильным ( желаемое возвращаемое значение: 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 , или этот вопрос переполнения стека .Однако все это (более или менее) сложный алгоритм прогнозирования.Я ищу гораздо более простое решение.Любая помощь приветствуется.

Ответы [ 2 ]

3 голосов
/ 09 мая 2019

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

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

0 голосов
/ 09 мая 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;
}

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

...