Как я могу оценить столбец чисел, чтобы найти изменения в повторяющейся последовательности? - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть таблица из 100 000 строк, и один столбец - это повторяющаяся серия чисел, представляющих «точку» в производственной линии робота.Мне нужно определить, когда меняется повторяющаяся последовательность.Последовательность состоит из четного числа и нечетного числа по обе стороны.Следовательно, числа в данной последовательности находятся на расстоянии 1 или 2, например, 32, 31, 33, 31, 33, 31, 33, 32, 31, 32, 31, 33, 32. Порядок трех чисел является случайным, за исключениемчисло не может следовать за собой.Последовательность может измениться, например, 33, 32, 31, 33, 31, 33, 31, 32, 31, 32, 33, 44, 45, 44, 43, 45, 43, 45, 43, 44, 29, 30,31, 29, 31, 30, 31, 29, 31, 29, 30,.,,

Я хочу иметь возможность обнаруживать каждое изменение в последовательности и помечать каждое изменение с 1 (оставляя значение по умолчанию 0 в строках, где нет изменений).

Там, где нет уверенности в том, принадлежит ли число к той или иной последовательности, например, 32, 31, 33, 33, 31, 30, 29, 30, 31 (последовательность была изменена с одной на около 32 наодин из которых основан на 30) предполагается, что последнее число, которое может принадлежать любой последовательности, относится к начальной последовательности.

Каждый шаг в последовательности чисел имеет уникальный идентификатор MoveID, разделенный по средствам и robotNum.

Я пытался использовать опережающие и запаздывающие числа для получения чисел до и после «пятна», находя разницу между суммой трех чисел перед точкой и суммой трех чисел после точки, чтобы увидетьесли разница превышает определенные пределы, что указывает на изменение в последовательности.(См. Следующий код).

SELECT moveID, facility, robotNum, spot, 
       CASE WHEN (((lastSpot1 + lastSpot2 + lastSpot3) - (nextSpot1 +  nextSpot2 +  nextSpot3))/3 BETWEEN -1.3 AND 1.3 ) 
       THEN 1
       ELSE 0 
       END 
       AS sequenceChange
     FROM
             ( SELECT facility, robotNum,
             , LEAD(spot,1,0) OVER(PARTITION BY facility, robotNum ORDER BY facility, robotNum, moveID ) AS nextSpot1
             , LEAD(spot,2,0) OVER(PARTITION BY facility, robotNum ORDER BY facility, robotNum, moveID ) AS nextSpot2
             , LEAD(spot,3,0) OVER(PARTITION BY facility, robotNum ORDER BY facility, robotNum, moveID ) AS nextSpot3
             , LAG(spot,1,0) OVER(PARTITION BY facility, robotNum ORDER BY facility, robotNum, moveID ) AS lastSpot1
             , LAG(spot,2,0) OVER(PARTITION BY facility, robotNum ORDER BY facility, robotNum, moveID ) AS lastSpot2
             , LAG(spot,3,0) OVER(PARTITION BY facility, robotNum ORDER BY facility, robotNum, moveID ) AS lastSpot3

            FROM SequenceTable1 
        ) t1
     ORDER BY facility, robotNum, moveID.

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

1 Ответ

0 голосов
/ 28 февраля 2019

Есть несколько простых отношений между последовательностями чисел, описанных в вопросе.Одна состоит в том, что разница между числами в последовательности никогда не превышает 2. Другая состоит в том, что четное число в каждой уникальной последовательности имеет модуль 2, а некоторые имеют модуль 4. При модуле - четное число, что нечетные числапринадлежать можно легко найти.Я идентифицировал все возможные логические комбинации, охватывающие различия между числами, чтобы обнаружить изменение в последовательности (есть 144 возможных комбинации, охватываемых 20 правилами), а также вычислить модуль.Ниже приведены операторы регистра SQL для правил, которые должны применяться последовательно.

                CASE    
                    WHEN    Spot = 1 OR Spot = 2   THEN 2   
                    WHEN    Spot = 3 and (POWER(lastSpot1,4) + POWER(Spot,4) + POWER(nextSpot2,4)) <114   THEN 2    
                    WHEN    Spot = 3 and nextSpot1 =  5   THEN 4    
                    WHEN    Spot = 3 and nextSpot1 = 4    THEN 4    
                    WHEN    Spot%4=0   THEN 4   
                    WHEN    Spot%4!=0 and Spot%2=0   THEN 2 
                    WHEN    Spot%2=1 and lastSpot1%2=1 AND (Spot -2 =lastSpot1 OR Spot+2 = lastSpot1) AND ((Spot+lastSpot1)/2)%4=0   THEN 4 
                    WHEN    Spot%2=1 and lastSpot1%2=1 AND (Spot -2 = lastSpot1 OR Spot+2 = lastSpot1) AND ((Spot+lastSpot1)/2)%4!=0 and ((Spot+lastSpot1)/2)%2=0   THEN 2  
                    WHEN    Spot%2=1 AND lastSpot1%2=0 AND (Spot-1 = lastSpot1 OR Spot+1 = lastSpot1) AND lastSpot1%4=0    THEN 4   
                    WHEN    Spot%2=1 AND lastSpot1%2=0 AND (Spot-1 = lastSpot1 OR Spot+1 = lastSpot1) AND lastSpot1%4!=0 AND lastSpot1%2=0     THEN 2   
                    WHEN    Spot%2=1 AND lastSpot1%2=1 AND (Spot-2 > lastSpot1 OR Spot+2 <  lastSpot1) AND nextSpot1%2=1 AND (Spot -2 = nextSpot1 OR Spot+2 = nextSpot1) AND  ((Spot+nextSpot1)/2)%4=0   THEN 4 
                    WHEN    Spot%2=1 AND lastSpot1%2=1 AND (Spot-2 > lastSpot1 OR Spot+2 <  lastSpot1) AND nextSpot1%2=1 AND (Spot -2 = nextSpot1 OR Spot+2 = nextSpot1) AND  ((Spot+nextSpot1)/2)%4!=0 AND and ((Spot+nextSpot1)/2)%2=0   THEN 2   
                    WHEN    Spot%2=1 AND lastSpot1%2=1 AND (Spot-2 > lastSpot1 OR Spot+2 <  lastSpot1) AND nextSpot1%2=0 AND (Spot - 1 = nextSpot1 OR Spot+1 = nextSpot1) AND  nextSpot1%4=0   THEN 4   
                    WHEN    Spot%2=1 AND lastSpot1%2=1 AND (Spot-2 > lastSpot1 OR Spot+2 <  lastSpot1) AND nextSpot1%2=1 AND (Spot -2 = nextSpot1 OR Spot+2 = nextSpot1) AND   nextSpot1%4!=0 AND and nextSpot1%2=0   THEN 2    
                    WHEN    Spot%2=1 AND lastSpot1%2=0 AND (Spot-1 > lastSpot1 OR Spot+1 <  lastSpot1) AND ((nextSpot1%2=1 AND (Spot-2 > nextSpot1 OR Spot+2 <  nextSpot1) ) OR(nextSpot1%2=0 AND (Spot-1 > nextSpot1 OR Spot+1 <  nextSpot1)))   THEN lastSpotStart    
                    WHEN    Spot%2=1 AND lastSpot1%2=1 AND (Spot-2 > lastSpot1 OR Spot+2 <  lastSpot1) AND ((nextSpot1%2=1 AND (Spot-2 > nextSpot1 OR Spot+2 <  nextSpot1) ) OR(nextSpot1%2=0 AND (Spot-1 > nextSpot1 OR Spot+1 <  nextSpot1)))   THEN lastSpotStart    
                    WHEN    Spot%2=1 AND lastSpot1%2=0 AND (Spot-12 > lastSpot1 OR Spot+1 <  lastSpot1) AND nextSpot1%2=0 AND (Spot - 1 = nextSpot1 OR Spot+1 = nextSpot1) AND  nextSpot1%4=0   THEN 4  
                    WHEN    Spot%2=1 AND lastSpot1%2=0 AND (Spot-1 > lastSpot1 OR Spot+1 <  lastSpot1) AND nextSpot1%2=0 AND (Spot - 1 = nextSpot1 OR Spot+1 = nextSpot1) AND   nextSpot1%4!=0 AND and nextSpot1%2=0   THEN 2   
                    WHEN    Spot%2=1 AND lastSpot1%2=0 AND (Spot-1 > lastSpot1 OR Spot+1 < lastSpot1) AND nextSpot1%2=1 AND  (Spot-2 = nextSpot1 OR Spot+2 = nextSpot1)  AND ((Spot + nextSpot1)/2)%4=0    THEN 4   
                    WHEN    Spot%2=1 AND lastSpot1%2=0 AND (Spot-1 > lastSpot1 OR Spot+1 < lastSpot1) AND nextSpot1%2=1 AND  (Spot-2 = nextSpot1 OR Spot+2 = nextSpot1)  AND lastSpot1%4!=0 AND  ((Spot + nextSpot1)/2)%2=0   THEN 2    
            ELSE 1      
            END AS seqMod

Далее, чтобы рассчитать индекс для каждого числа в каждой последовательности (индекс - это четное число последовательностей), я использовал следующий код (спасибо https://stackoverflow.com/users/15498/damien-the-unbeliever):

            CASE 
            WHEN seqMod = 4 AND (Spot = 1 OR Spot = 2) THEN 2  -- for when a robot that started at index 4 returns to index 2
            ELSE 
            CONVERT(int, ROUND((Spot +  CASE    WHEN seqMod = 2 THEN 2 ELSE 0 END )/4.0,0)* 4 - CASE    WHEN seqMod = 2 THEN 2 ELSE 0 END   )
            END AS spotIndex

С помощью индекса легко обнаружить изменения от одной последовательности к другой

...