2017-01-09 11 views
1

В настоящее время я пытаюсь нормализовать данные с помощью VBA в Excel. Поэтому моя книга импортирует несколько файлов csv и записывает их в разные рабочие листы, все они построены следующим образом.Быстрый способ нормализации данных с помощью VBA (Excel)

  • Первая строка: Заголовок
  • Первой колонка: х-оси (для черчения)
  • Второго столбца п-я колонка: Y-значение

Теперь я хочу, чтобы нормализовать все столбцы из 2 до n (деление на максимальное значение каждого столбца). Вот функция, я использую до сих пор:

Sub NormalizeData(dataName) 

cs = Worksheets(dataName).UsedRange.SpecialCells(xlCellTypeLastCell).Column 
rs = Worksheets(dataName).UsedRange.SpecialCells(xlCellTypeLastCell).Row 

For col = 2 To cs 
    maxValue = Application.WorksheetFunction.Max(Worksheets(dataName).Columns(col)) 

    For r = 2 To rs 
     Worksheets(dataName).Cells(r, col) = Worksheets(dataName).Cells(r, col)/maxValue 
    Next r 
Next col 
End Sub 

Этот подход работает, но из-за объема данных, это очень медленно. Есть ли способ увеличить скорость? Я уже включил обновление экрана.

Спасибо вам большое за вашу помощь !!!

ответ

2

Вот к югу, который нормализует число в прямоугольном диапазоне. Вы можете решить, на какой диапазон вы хотите, чтобы нормализовать и затем передать этот диапазон в этот суб:

Sub NormalizeRange(R As Range) 
    'assumes that R is a rectangular range 
    'will throw an error if any column has max 0 

    Dim vals As Variant, maxes As Variant 
    Dim i As Long, j As Long, m As Long, n As Long 

    m = R.Rows.Count 
    n = R.Columns.Count 
    ReDim maxes(1 To n) 

    With Application.WorksheetFunction 
     For i = 1 To n 
      maxes(i) = .Max(R.Columns(i)) 
     Next i 
    End With 

    vals = R.Value 
    For i = 1 To m 
     For j = 1 To n 
      vals(i, j) = vals(i, j)/maxes(j) 
     Next j 
    Next i 
    R.Value = vals 
End Sub 

Это будет более эффективным, чем то, что вы в настоящее время, так как он перемещает значения между таблицей и VBA в неконтролируемой передаче данных, а не через большое количество отдельных операций чтения/записи. Он также избегает таких вещей, как проблемы с обновлением экрана и промежуточный перерасчет функций в зависимости от этих значений.

+0

John Coleman благодарит вас за ваш юнит. До сих пор он отлично работает. Преимущество вашего подхода и подхода JanB заключается в том, что вам не нужен пустой рабочий лист. – Stefan

3

Используйте другой лист и PasteSpecial. Предполагая, что ws1 содержит данные и ws2 в настоящее время не используется:

with ws2.Range(.Cells(2,2), .Cells(rs, cs)) 
    .value = maxValue 
    .copy 
end with 
ws1.Range(.Cells(2,2), .Cells(rs, cs)).PasteSpecial _ 
Operation:=xlPasteSpecialOperationDivide 
Application.CutCopyMode = False 
+0

Здесь я думал о публикации xlDivide и не был уверен, будет ли он быстрее, чем у него ... Я видел, как он перечислил несколько листов для всех файлов, поэтому остановился сам. – Cyril

+0

Большое спасибо, я написал небольшой тестовый скрипт с вашим и @John Coleman's sub, и он отлично работает. Я собираюсь реализовать его в своем проекте позже, чтобы проверить его. JanB: Одно небольшое замечание, есть опечатка внутри вашего xlPasteSpecialOperationDevide. – Stefan

Смежные вопросы