Я понимаю, что вы хотите разделить свои данные на группы, где максимальная разница от самого большого к меньшему составляет ± 5%. Я написал код Apps Script , который может сделать это в вашем Листе. Во-первых, я написал образец листа с именами учащихся и результатами тестов (от 0 до 10) вместо имен и роста; Я объясню почему позже. Это начальное состояние листа примера:
В столбце Group
код удалит идентификатор группы как целое число, начиная с 0 Это код:
function so62060595() {
var dataColumn = 2; // Column B
var groupColumn = 3; // Column C
var dataSheet = SpreadsheetApp.getActive().getActiveSheet();
var dataRange = dataSheet.getRange(2, 1, dataSheet.getLastRow() - 1, dataSheet
.getLastColumn()).sort({
column: dataColumn,
ascending: false
});
var data = dataRange.getValues();
var groupingPercentage = 5 / 100 // 5%
var upperBound = data[0][dataColumn - 1];
var groupID = 0;
for (var r = 0; r < data.length; r++) {
if (upperBound - upperBound * groupingPercentage <= data[r][dataColumn -
1] + data[r][dataColumn - 1] * groupingPercentage) {
// Include in the same group
data[r][groupColumn - 1] = groupID;
} else {
// Create a new group
var groupID = groupID + 1;
var upperBound = data[r][dataColumn - 1];
data[r][groupColumn - 1] = groupID;
}
}
dataRange.setValues(data);
}
Первое, что делает код, - открывает лист с SpreadsheetApp.getActive()
, Spreadsheet.getActiveSheet()
. После этого код ищет диапазон данных с Sheet.getRange()
(обратите внимание, как он использует Sheet.getLastRow()
и Sheet.getLastColumn()
, чтобы найти размер диапазона) и сортирует его с помощью Range.sort()
, используя столбец оценки в качестве ссылки. Позже он считывает диапазон с помощью Range.getValues()
. Кроме того, я инициализировал некоторые переменные, такие как столбцы идентификатора и группы, желаемый процент группировки (5%) в этом случае и исходный идентификатор группы (0
).
После всей этой инициализации код будет повторяться каждую строку и проверьте, находится ли значение данных (Score
в примере) на расстоянии ± 5% от верхней границы группы (самое высокое значение в группе). Если значение находится в диапазоне ± 5%, идентификатор группы будет удален. Если он не входит в диапазон, будет сгенерирован новый идентификатор группы, а верхняя граница будет взята из этой записи. Процесс будет продолжаться до тех пор, пока все записи не получат идентификатор группы, после чего данные будут внесены в таблицу с Range.setValues()
. Окончательный результат выглядит так:
А теперь, почему я использовал результаты тестов вместо роста? Что ж, посмотрите, что происходит с примером высот с использованием предыдущего кода:
Генерируются только две группы (0
и 1
) потому что расстояние между реалистичными c высотами меньше ± 5%. Я надеюсь, что мой ответ поможет вам, но не стесняйтесь задавать мне дополнительные сомнения.
ОБНОВЛЕНИЕ
На основе обновления вопроса в вашем комментарии я изменил сценарий. Если я правильно понимаю, вам нужна средняя точка в каждой группе и рассчитываются границы группы на основе этой средней точки плюс / минус 5%. Если мое предположение верно, вы можете использовать следующий код:
function calculateGroupBounds(groupingPercentage, groupUpperBound) {
var groupBounds = {};
groupBounds['groupUpperBound'] = groupUpperBound;
groupBounds['groupMidpoint'] = 100 * groupUpperBound / (100 +
groupingPercentage);
groupBounds['groupLowerBound'] = (100 - groupingPercentage) * groupBounds[
'groupMidpoint'] / 100;
return groupBounds;
}
function so62060595B() {
// Sheet reading
var dataColumn = 2; // Column B
var groupColumn = 3; // Column C
var dataSheet = SpreadsheetApp.getActive().getActiveSheet();
var dataRange = dataSheet.getRange(2, 1, dataSheet.getLastRow() - 1, dataSheet
.getLastColumn()).sort({
column: dataColumn,
ascending: false
});
var data = dataRange.getValues();
// Group initialization
var groupingPercentage = 5; // 5%
var groupID = 0;
var groupUpperBound = data[0][dataColumn - 1];
var groupBounds = calculateGroupBounds(groupingPercentage, groupUpperBound)
var groupMidpoint = groupBounds['groupMidpoint'];
var groupLowerBound = groupBounds['groupLowerBound'];
for (var r = 0; r < data.length; r++) {
if (data[r][dataColumn - 1] <= groupUpperBound && data[r][dataColumn - 1] >=
groupLowerBound) {
// Include in the same group
data[r][groupColumn - 1] = groupID;
} else {
// Create a new group
var groupID = groupID + 1;
var upperBound = data[r][dataColumn - 1];
var groupBounds = calculateGroupBounds(groupingPercentage,
upperBound)
var groupMidpoint = groupBounds['groupMidpoint'];
var groupLowerBound = groupBounds['groupLowerBound'];
data[r][groupColumn - 1] = groupID;
}
}
dataRange.setValues(data);
}
Этот новый код использует те же методы скрипта приложений, что и предыдущий, и включает новую функцию (calculateGroupBounds()
) для вычисления верхнего и нижние границы и середина. В итерации данных код проверяет, находится ли значение между верхней и нижней границей, и если это так, группа iD будет удалена. Если этого не произойдет, будет создана новая группа. Это результат с теми же данными примера, что и предыдущий код:
И это результат с таблицей высот:
Эти результаты такие же, как и в предыдущем коде, хотя мы используем другой подход во втором коде. Это связано с тем, что в первом коде я использовал математические свойства для разделения данных на группы ± 5% без вычисления средней точки. Пожалуйста, задайте мне любые сомнения, если вам все еще нужна помощь.