- Регистрация
- 21.02.2016
- Сообщения
- 2 046
- Реакции
- 830
- Баллы
- 113
Одно из самых банальных вещей что может оценивать антифрод – это кликстрим. Т.е. куда кликали и через какое время. ЖУТКО БАНАЛЬНО и просто. Куда кликали – тут отдельный разговор. А вот КОГДА кликали – это тут конь не валялся. И:
- Где паузы вообще есть
- Длительность пауз
- Распределение по длительностям пауз
Влияет на определение ты бот или живой человек. А так же на выживаемость аккаунтов.
Банально за какой-то длительный период времени собирается по профилю или аккаунту его клик стрим и все паузы нормируются по длительности и распределению. И тут выясняется что ты бот)) И аккаунт улетел в трубу)) Хотя, казалось бы, жил уже много месяцев… Все же было хорошо…
Между действиями стоит
И начнем с рандома.
Общий статический new Random() на весь проект — частая ошибка в многопоточных шаблонах. Она проявляется не сразу: при нагрузке генератор начинает отдавать нули, и все «случайные» паузы внезапно становятся одинаковым. Ниже код который позволяет сделать его сильно более уникальным.
Если делать обычную паузу ДАЖЕ В ДИАПОЗОНЕ, то получает «равномерное распределение»
Банальный квадрат)) Где все возможные времена задержек ложатся в линию)) Просто, понятно, тупо и паливно)))
Но ЭТО ЛУЧШЕ, чем вообще отсутствие пауз или фиксированная пауза.
Середина диапазона выпадает чаще, края реже: колокол, у которого ±3 сигмы совпадают с границами. Паузы группируются вокруг типичного значения, а не размазываются по диапазону равномерно, как у
Сама функция например такая как Гаусово распределение, которое можно уже добавлять в паузу
Функция терпима к ошибкам вызова: равные или перевёрнутые границы не роняют шаблон.
Недостаток.
- Распределение симметричное. Паузы короче типичной встречаются так же часто, как длиннее. У человека не так: быстрее определённого предела он не может, а медленнее может сколько угодно. Для длительностей это главный изъян.
- Нет длинного хвоста. Значения никогда не выходят за `max`, а живые паузы иногда в разы длиннее обычных.
- Типичное значение не задать отдельно. Центр всегда посередине диапазона: если нужна «обычно 300 мс, но бывает до 2 секунд», диапазоном это не выразить.
- Края выпадают реже, чем должны. Из-за округления границам достаётся только половина ячейки. Мелочь, но на больших выборках заметная.
Надо искать хвосты… Где у нас обычно хвосты?
Возвращает длительность, у которой половина значений меньше медианы, а половина больше. Короткие паузы сгруппированы плотно, длинные уходят в плавный хвост
ВОТ ОНИ ХВОСТЫ!
Например,
График ниже. Чтобы не парить математикой – значения показаны на графике где какое для функции.
Сама функция
Ниже функция стандартного гаусового отклонения прикладного значения.
Возвращает число из стандартного нормального распределения: чаще всего около нуля, примерно в 68 % случаев в пределах ±1.
- Форма распределения совпадает с формой реальных человеческих интервалов: времени реакции, пауз между нажатиями клавиш, времени на странице. Паузы проходят проверку согласия, которую не проходят ни ровные, ни равномерные, ни нормальные.
- Задаётся двумя понятными числами: медиана — «обычно столько», сигма — «насколько бывает дольше».
- Длинный хвост получается сам, без костыля
Вызывается, например, так
Общее правило простое. Там, где пауза видна сайту как интервал между действиями человека, берите логнормальное распределение. Там, где пауза нужна только самому шаблону, например подождать загрузку, форма распределения неважна: важны прерываемость и разумный предел.
Всем спасибо.
Лайки, комментарии, подписки, жмякалки во все места приветствуются.
p.s. Если по алгоритму есть замечания – рвите меня на куски)) По программированию и оформлению можно не говорить))
- Где паузы вообще есть
- Длительность пауз
- Распределение по длительностям пауз
Влияет на определение ты бот или живой человек. А так же на выживаемость аккаунтов.
Банально за какой-то длительный период времени собирается по профилю или аккаунту его клик стрим и все паузы нормируются по длительности и распределению. И тут выясняется что ты бот)) И аккаунт улетел в трубу)) Хотя, казалось бы, жил уже много месяцев… Все же было хорошо…
А теперь паузы.
Между действиями стоит
Thread.Sleep(2000). Живой человек так не делает: у него нет двух одинаковых интервалов, короткие паузы встречаются часто, длинные редко, но бывают в разы длиннее обычных. Ровные или равномерно случайные паузы отличаются от человеческих обычной статистической проверкой, без всякого машинного обучения.И начнем с рандома.
Общий статический new Random() на весь проект — частая ошибка в многопоточных шаблонах. Она проявляется не сразу: при нагрузке генератор начинает отдавать нули, и все «случайные» паузы внезапно становятся одинаковым. Ниже код который позволяет сделать его сильно более уникальным.
C#:
/// <summary>Экземпляр Random, свой для каждого потока.</summary>
[ThreadStatic]
private static Random _threadRnd;
/// <summary>
/// Потокобезопасный генератор случайных чисел: по одному экземпляру на поток.
/// Класс Random не потокобезопасен: при одновременном обращении из нескольких
/// потоков ZennoPoster его внутреннее состояние портится и Next() начинает
/// возвращать нули. Поэтому у каждого потока свой экземпляр со своим сидом.
/// </summary>
public static Random Rnd
{
get
{
if (_threadRnd == null)
_threadRnd = new Random(Guid.NewGuid().GetHashCode());
return _threadRnd;
}
}
Обычная пауза и равномерное распределение
Thread.Sleep(rnd.next(2000, 3000))Если делать обычную паузу ДАЖЕ В ДИАПОЗОНЕ, то получает «равномерное распределение»
Банальный квадрат)) Где все возможные времена задержек ложатся в линию)) Просто, понятно, тупо и паливно)))
Но ЭТО ЛУЧШЕ, чем вообще отсутствие пауз или фиксированная пауза.
Нормальное распределение в диапазоне
Середина диапазона выпадает чаще, края реже: колокол, у которого ±3 сигмы совпадают с границами. Паузы группируются вокруг типичного значения, а не размазываются по диапазону равномерно, как у
Rnd.NextСама функция например такая как Гаусово распределение, которое можно уже добавлять в паузу
Thread.Sleep. Правильное распределение же важнее, да?))
Код:
/// <summary>
/// Возвращает случайное целое число из диапазона [min, max],
/// распределённое по нормальному (гауссову) закону.
/// Равные границы возвращают само значение, перевёрнутые меняются местами.
/// </summary>
/// <returns>Целое число из [min, max]; центр диапазона выпадает чаще краёв.</returns>
public static int GaussianRandom(int min, int max)
{
if (min == max) return min;
if (min > max)
{
int swap = min;
min = max;
max = swap;
}
Random _random = CommonCode.Rnd;
// Матожидание - середина диапазона, сигма подобрана так,
// чтобы правило трёх сигм накрывало весь диапазон.
double mean = (min + max) / 2.0;
double sigma = (max - min) / 6.0;
// Преобразование Бокса - Мюллера: две равномерные величины -> одна нормальная
double u1;
do { u1 = _random.NextDouble(); } while (u1 == 0);
double u2 = _random.NextDouble();
double z = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Cos(2.0 * Math.PI * u2);
double value = mean + z * sigma;
// Хвосты распределения обрезаем по границам диапазона
int result = (int)Math.Round(value);
return Math.Max(min, Math.Min(result, max));
}
Функция терпима к ошибкам вызова: равные или перевёрнутые границы не роняют шаблон.
Недостаток.
- Распределение симметричное. Паузы короче типичной встречаются так же часто, как длиннее. У человека не так: быстрее определённого предела он не может, а медленнее может сколько угодно. Для длительностей это главный изъян.
- Нет длинного хвоста. Значения никогда не выходят за `max`, а живые паузы иногда в разы длиннее обычных.
- Типичное значение не задать отдельно. Центр всегда посередине диапазона: если нужна «обычно 300 мс, но бывает до 2 секунд», диапазоном это не выразить.
- Края выпадают реже, чем должны. Из-за округления границам достаётся только половина ячейки. Мелочь, но на больших выборках заметная.
Надо искать хвосты… Где у нас обычно хвосты?
ЛонгНормальное распределение
Возвращает длительность, у которой половина значений меньше медианы, а половина больше. Короткие паузы сгруппированы плотно, длинные уходят в плавный хвост
ВОТ ОНИ ХВОСТЫ!
Например,
LogNormalRandom(600, 0.42, 120, 4000) чаще всего даёт 400–900 мс, иногда 1,5–2 секунды и совсем редко около 3.График ниже. Чтобы не парить математикой – значения показаны на графике где какое для функции.
Сама функция
Код:
/// <summary>
/// Логнормальное распределение: колокол с длинным правым хвостом.
/// </summary>
/// <param name="dMedian">Медиана распределения.</param>
/// <param name="dSigma">Логарифмическое СКО: чем больше, тем длиннее правый хвост. Обычно 0.3-0.5.</param>
/// <param name="dMin">Нижняя граница.</param>
/// <param name="dMax">Верхняя граница.</param>
/// <remarks>
/// Нужно везде, где величина - это человеческая длительность. Нормальное распределение этот хвост не даёт,
/// равномерное не даёт и колокола - оба отличимы от живых данных обычной
/// проверкой согласия.
///
/// Медиана, а не среднее: у логнормального они не совпадают, и именно медиана
/// соответствует привычному «типичному значению».
/// </remarks>
private static double LogNormalRandom(double dMedian, double dSigma, double dMin, double dMax)
{
double d = dMedian * Math.Exp(dSigma * NextGaussianStd());
if (d < dMin) d = dMin;
if (d > dMax) d = dMax;
return d;
}
Ниже функция стандартного гаусового отклонения прикладного значения.
Возвращает число из стандартного нормального распределения: чаще всего около нуля, примерно в 68 % случаев в пределах ±1.
Код:
/// <summary>
/// Стандартное нормальное отклонение: среднее 0, СКО 1.
/// </summary>
/// <remarks>
/// Преобразование Бокса-Мюллера. В отличие от GaussianRandom не привязано к
/// диапазону и служит основой для остальных распределений: масштабировав его,
/// получаем и усечённое нормальное, и логнормальное.
/// </remarks>
private static double NextGaussianStd()
{
double u1 = 1.0 - Rnd.NextDouble();
double u2 = 1.0 - Rnd.NextDouble();
return Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
}
LogNormalRandom - Это самая полезная функция в наборе.- Форма распределения совпадает с формой реальных человеческих интервалов: времени реакции, пауз между нажатиями клавиш, времени на странице. Паузы проходят проверку согласия, которую не проходят ни ровные, ни равномерные, ни нормальные.
- Задаётся двумя понятными числами: медиана — «обычно столько», сигма — «насколько бывает дольше».
- Длинный хвост получается сам, без костыля
Вызывается, например, так
Thread.Sleep((int)LogNormalRandom(200, 0.42, 120, 400)); Параметры, лучше, конечно, свои задавать. Чтобы весь интернет резко не стал одинаково себя вести))Общее правило простое. Там, где пауза видна сайту как интервал между действиями человека, берите логнормальное распределение. Там, где пауза нужна только самому шаблону, например подождать загрузку, форма распределения неважна: важны прерываемость и разумный предел.
Всем спасибо.
Лайки, комментарии, подписки, жмякалки во все места приветствуются.
p.s. Если по алгоритму есть замечания – рвите меня на куски)) По программированию и оформлению можно не говорить))
Последнее редактирование:


