Страницы: 1
RSS
Bootstrap Ускорение алгоритма, Ускорить алгоритм обработки больших случаных выборок
 
Здравствуйте.
Тестирую метод бутстрапа на примере продаж товаров.
В общем что хочу получить на выходе:
У меня есть массив продаж за определенный период (Сейчас около 1500 товаров). Есть еще массив остатков на складе.
Я хочу взять каждый товар, вычленить массив продаж, но только с условием что товар был на складе (там еще есть  пара условий, но не суть), далее сгенерировать 10000 недель случайных продаж товара на основе существующей истории.
Во всей этой ситуации есть проблема: скорость обработки и генерации 10000 (хотя бы) строк по 1500 товарам занимает почему то огромное количество времени (10 сек на 1 товар).

Если кто то сталкивался с задачей, может есть методы ускорить код. Привожу код ниже с комментариями.
Код
    Dim mBootS() As Variant 'Результирующий массив с распределением (перезаписывается для каждого товара)
    Dim mViborkaProd() As Variant 'массив продаж по товару(перезаписывается для каждого товара)
    Dim mBootSViv() 'Этот массив содержит результаты нужных мне процентилей
    ReDim mBootSViv(1 To lRowBase - 1, 1 To 8)

    
    For i = 1 To lRowBase - 1 '(от 1 до 1500 товаров)
        If mBaseFull(i, 8) <> 0 And mBaseFull(i, 8) <> "" Then 'Это ограничение на некоторые виды товаров, которые не имеет смысла обрабатывать (снятые с продаж и т.д.)

            l = 0
            ReDim mViborkaProd(1 To 1)
            For j = 1 To KolDay 'от первого дня периода продаж до последнего
                If mOstDay(i, j) <> "Missing" And mOstDay(i, j) <> 0 And mOstDayPometki(i, j) <> "Days off" Then 'Еще одно ограничение на товары (Не было в продаже, не работал магазин и т.д.)
                    l = l + 1
                    ReDim Preserve mViborkaProd(1 To l)
                    mViborkaProd(l) = Abs(mProdDay(i, j)) 'Где ProdDay(i, j) - это массив продаж
                End If
            Next j

            ReDim mBootS(1 To 10001)
            Randomize 'Не уверен что правильно использую данную функцию
            For k = 1 To 10001
                For j = 1 To 7
                    mBootS(k) = mBootS(k) + mViborkaProd(Int((l * Rnd) + 1)) 'сумма сгенерированных продаж за неделю (сами дни не нужно хранить, интересует только сумм)
                Next j
            Next k
           
            SortArray mBootS, True 'Сортирую массив
          'Извлекаю только интересующие меня процентили во всем распределении, остальное потом будет перезаписано
            mBootSViv(i, 1) = mBase(i, 1) '
            mBootSViv(i, 2) = mBootS(1000) 'Мин
            mBootSViv(i, 3) = mBootS(750) '25%
            mBootSViv(i, 4) = mBootS(500) '50%
            mBootSViv(i, 5) = mBootS(200) '80%
            mBootSViv(i, 6) = mBootS(100) '90%
            mBootSViv(i, 7) = mBootS(50) '95%
            mBootSViv(i, 8) = mBootS(1) '100%

        End If
    Next i
 
 
Доброе время суток.
Первое что бросается в глаза - использование
Код
ReDim Preserve mViborkaProd(1 To l)
Массив же используется только для переноса значений из mOstDay по индексу l.
Тогда объявите массив с запасом
Код
Dim mViborkaProd(1 To 100000)

и используйте без постоянного изменения размера. Размер выборки вы всегда знаете по значению l.
 
Спасибо, сделал. Тестирую для выборки в 1000 штук. Было 195 сек, стало 187.
Мне вот просто интересно у кого сколько подобные операции занимают времени. 1500 * 10000 операций.
А Randomize правильно использован?
 
И еще у меня идет перебор по одному, может как то надо заранее создать таблицы случайных чисел, а потом по ним пройтись циклом.
____
Хотя, я так уже делал. Основной тормоз видимо в выдергивании случайных чисел из одного массива и добавление в другой массив с операцией сложения и сортирования.
Изменено: Mirai - 27.01.2017 08:12:22
 
Цитата
Mirai написал:
Основной тормоз видимо в выдергивании случайных чисел из одного массива и добавление в другой массив с операцией сложения и сортирования.
Для этого проведите анализ работы
Код
Dim vTimer As Single
'Перед каждым блоком/циклом
vTimer = Timer
'После завершения блока/циклка
Debug.Print "Блок выполнялся " & CStr(Timer - vTimer)
Чтобы найти самое долгое место. Сортировка у вас каким алгоритмом выполняется? Может имеет смысл числовые массивы mViborkaProd, mBootSViv, mBootSViv объявить с типом Double, чтобы не выполнялось при каждом чтении/записи предобразование из/в Variant в Double.
 
Спасибо за совет, я так и сделал. После 6 часов разборки, понял, что проблема была в сортировке. Проверил около 10 вариантов и самый быстрый оказался этот, скорость выросла с 215 сек до 1 сек. Мне нужно было сортировать числа.
Код
Public Sub QuickSort(vArray As Variant, inLow As Long, inHi As Long)

  Dim pivot   As Variant
  Dim tmpSwap As Variant
  Dim tmpLow  As Long
  Dim tmpHi   As Long

  tmpLow = inLow
  tmpHi = inHi

  pivot = vArray((inLow + inHi) \ 2)

  While (tmpLow <= tmpHi)

     While (vArray(tmpLow) < pivot And tmpLow < inHi)
        tmpLow = tmpLow + 1
     Wend

     While (pivot < vArray(tmpHi) And tmpHi > inLow)
        tmpHi = tmpHi - 1
     Wend

     If (tmpLow <= tmpHi) Then
        tmpSwap = vArray(tmpLow)
        vArray(tmpLow) = vArray(tmpHi)
        vArray(tmpHi) = tmpSwap
        tmpLow = tmpLow + 1
        tmpHi = tmpHi - 1
     End If

  Wend

  If (inLow < tmpHi) Then QuickSort vArray, inLow, tmpHi
  If (tmpLow < inHi) Then QuickSort vArray, tmpLow, inHi

End Sub
Работает очень быстро и хорошо сортирует по возрастанию числа (про остальное не знаю).
И еще что касается скорости: до этого (с пузырьковой сортировкой), считал для 1000 генераций 190 сек. Сейчас для 10000 генераций считает 40 сек.
Изменено: Mirai - 28.01.2017 05:01:15
Страницы: 1
Наверх