Как перебрать неровные блоки данных - PullRequest
0 голосов
/ 10 июня 2019

Так что в основном я имею дело с листом данных, примерно до 200 000 строк.Данные немного отформатированы, как показано ниже (поддельные данные).Я пытаюсь проанализировать каждый цикл, чтобы убедиться, что определенные диапазоны температуры и давления были достигнуты для каждого цикла (например, температура находится в пределах 120-130 для любого данного цикла).

cycle    temperature    pressure 
  1           120          321
  1           121          332
  1           122          323
  2           123          334
  2           124          326
  3           125          337
  3           126          328
  3           127          339
  3           128          320
  4           129          334    

Я довольноуверенный в том, что может использовать некоторые операторы if, чтобы увидеть, был ли достигнут каждый темп / давление, но та часть, которая доставляет мне проблемы, - это возможность разбить его на способность анализировать цикл за циклом (например, цикл 1 находится в пределах диапазона,цикл 2 находится в пределах досягаемости).Это было бы довольно просто, если бы циклы имели одинаковую длину, но они обычно изменяются на 1 или 2 значения.

Моя текущая идея состояла в том, чтобы посмотреть на первое значение цикла, а затем перебрать строки.Если значение цикла каждой строки равно желаемому значению (начиная с цикла 1), тогда выполняются нужные мне операторы if.Если мы достигаем цикла 2, то мы увеличиваем var, чтобы он равнялся циклу 2.

var = ThisWorkbook.Sheets("Data").Range("A2")
For i = 2 To lastRow

    If ThisWorkbook.Sheets("Data").Cells(i, 1) = var Then
        'various if statements go here
    Else
        var = var + 1
    End If
next i

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

В основном просто нужна некоторая помощь в том, как подумать о разделении этого на разделы по циклам.Интуиция подсказывает мне, что я вложен в циклы, но я не уверен, что смогу сказать «это новый цикл, перейдите к следующему циклу».

Ответы [ 3 ]

1 голос
/ 10 июня 2019

Вы должны быть в состоянии сделать что-то подобное (при условии, что ColA отсортировано по cycle и не имеет пустых ячеек)

Dim c as range, i as long

Set c = ThisWorkbook.Sheets("Data").Range("A2")

Do While c.Value <> ""
    i = application.Countif(c.parent.columns(1),c.value)

    'Process i rows of data


    Set c = c.offset(i, 0) '<< start of next block
Loop
0 голосов
/ 11 июня 2019

Использование подхода Variant Array будет намного быстрее для 200 000 строк

Простой цикл for для массива, идентифицирующий первую и последнюю строку каждого цикла, затем цикл для обработки данных.

Что-то вроде этого

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

На моем оборудовании работает за 1,7 с на случайном наборе данных, 200 000 строк

Sub Demo()
    Dim rngDat As Range
    Dim rngRes As Range
    Dim dat As Variant
    Dim res As Variant
    Dim FirstOfCycle As Long
    Dim LastOfCycle As Long
    Dim Cycle As Long
    Dim i As Long, j As Long

    Set rngDat = Range(Cells(2, 3), Cells(Rows.Count, 1).End(xlUp))
    'Example: set return range to 4 columns next to data
    Set rngRes = rngDat.Columns(rngDat.Columns.Count + 1).Resize(, 8)
    dat = rngDat.Value2
    rngRes.ClearContents
    res = rngRes.Value2

    FirstOfCycle = 1
    For i = 1 To UBound(dat, 1) - 1
        If dat(i + 1, 1) <> dat(i, 1) Then
            LastOfCycle = i
            Cycle = dat(i, 1)
            ProcessCycle dat, res, FirstOfCycle, LastOfCycle
            FirstOfCycle = i + 1
        End If
    Next
    If dat(i, 1) = dat(FirstOfCycle, 1) Then
        ProcessCycle dat, res, FirstOfCycle, i
    Else
        ProcessCycle dat, res, i, i
    End If


    rngRes.Value = res

End Sub

Private Sub ProcessCycle(dat As Variant, result As Variant, FirstOfCycle As Long, LastOfCycle As Long)
    Dim i As Long
    Dim MnT As Double, MxT As Double
    Dim AvgT As Double, SdT As Double
    Dim SumT As Double, SumT2 As Double
    Dim MnP As Double, MxP As Double
    Dim AvgP As Double, SdP As Double
    Dim SumP As Double, SumP2 As Double

    MnT = dat(FirstOfCycle, 2)
    MxT = dat(FirstOfCycle, 2)
    MnP = dat(FirstOfCycle, 3)
    MxP = dat(FirstOfCycle, 3)
    For i = FirstOfCycle To LastOfCycle
        If dat(i, 2) < MnT Then MnT = dat(i, 2)
        If dat(i, 2) > MxT Then MxT = dat(i, 2)
        If dat(i, 3) < MnP Then MnP = dat(i, 3)
        If dat(i, 3) > MxP Then MxP = dat(i, 3)
        SumT = SumT + dat(i, 2)
        SumT2 = SumT2 + dat(i, 2) ^ 2
        SumP = SumP + dat(i, 3)
        SumP2 = SumP2 + dat(i, 3) ^ 2
    Next
    result(FirstOfCycle, 1) = MnT
    result(FirstOfCycle, 2) = MxT
    result(FirstOfCycle, 3) = SumT / (LastOfCycle - FirstOfCycle + 1)
    result(FirstOfCycle, 4) = Sqr(SumT2 / (LastOfCycle - FirstOfCycle + 1) - result(FirstOfCycle, 3) ^ 2)

    result(FirstOfCycle, 5) = MnP
    result(FirstOfCycle, 6) = MxP
    result(FirstOfCycle, 7) = SumP / (LastOfCycle - FirstOfCycle + 1)
    result(FirstOfCycle, 8) = Sqr(SumP2 / (LastOfCycle - FirstOfCycle + 1) - result(FirstOfCycle, 7) ^ 2)
End Sub
0 голосов
/ 10 июня 2019

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

Public Function findBadCycles(rngRangeToCheck As Range) As Collection

    Dim dblMinTemp As Double
    Dim dblMaxTemp As Double
    Dim dblMinPress As Double
    Dim dblMaxPress As Double

    dblMinTemp = 120
    dblMaxTemp = 130
    dblMinPress = 320
    dblMaxPress = 340

    Dim colBadCycles As Collection
    Set colBadCycles = New Collection

    Dim i As Long
    For i = 2 To rngRangeToCheck.Rows

        If rngRangeToCheck.Cells(i, 2) < dblMinTemp Or rngRangeToCheck.Cells(i, 2) > dblMaxTemp Then
            colBadCycles.Add rngRangeToCheck.Cells(i, 1).Value
        elseif (rngRangeToCheck.Cells(i, 3) < dblMinPress) Or (rngRangeToCheck.Cells(i, 3) > dblMaxPress):
            colBadCycles.Add rngRangeToCheck.Cells(i, 1).Value
        End If

    Next i

    Set findBadCycles = colBadCycles

End Function
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...