Русский
Русский
English
Статистика
Реклама

Учебный процесс

Перевод 10 лучших игр по программированию, которые улучшат ваши навыки

11.03.2021 20:12:02 | Автор: admin

Вы помните далёкие дни из детства, когда вы, проводили целый день, а иногда даже не ели целый день, чтобы поиграть в игры на Nintendo? (Ах, дни Mario и Contra!!!)

С того времени игры претерпели гигантские преобразования и сфера стала более обширной. Это уже не просто хобби. Сейчас в Интернете доступно множество игр, связанных с программированием, и вы можете использовать их чтобы изучить и отточить свои скилы в увлекательной форме. Более того, эти игры могут помочь вам улучшить навыки решения задач, поскольку вам нужно будет решать задачи различной сложности, а также соревноваться с другими опытными программистами по всему миру. Специально к старту новых потоков курсов Fullstack-разработчик на Python, разработка на C# и разработка на Java, в этой статье мы отобрали несколько таких игр, играя в которые можно параллельно качать и себя самого.

1. Untrusted

Приключения доктора Эвала!

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

В игре есть несколько уровней, таких как cellBlockA, где вы будете генерировать и удалять стены, theLongWayOut, в котором вам нужно создать новый выход, и многое другое. Игра довольно увлекательное путешествие, если вы обладаете хорошими знаниями концепций и программирования JavaScript. Интерфейс игры выглядит так:

2. Robocode

Было бы здорово изучать программирование, и создавать боевых роботов-танков (звучит увлекательно, правда?).

Да, вы можете сделать это в известной игре Robocode. Robocode позволяет разработать боевого робота-танка с использованием Java или .NET, для борьбы с другими танками. Вам нужно написать ИИ для робота, чтобы он знал, что делать и как реагировать на события, происходящие на поле битвы.

Игра очень полезна для изучения и практики нескольких языков программирования, таких как Java, Scala, и C# . Она также поможет вам попасть в сферу искусственного интеллекта . Более того, Robocode предоставляет вам полноценную среду разработки: есть собственный установщик, встроенный редактор роботов и компилятор Java. Кроме того, Robocode это проект с открытым исходным кодом, и вы все можете придумывать свои собственные надстройки или режимы, чтобы продемонстрировать свои навыки разработки.

3. Elevator Saga

Elevator Saga поможет вам продемонстрировать свои навыки в JavaScript в контексте программирования движения лифтов для эффективной перевозки людей. Задачи самые разные, начиная с простых: перевезти 15 человек за 60 секунд или меньше и т. д., И они постепенно усложняются. Вам нужно придумать оптимизированный алгоритм, чтобы сократить время ожидания пассажиров. Игра действительно очень полезна для работы над вашими навыками JavaScript и подходами к оптимизации алгоритмов.

Кроме того, интерфейс Elevator Saga довольно прост, всё, что вам нужно, ввести свой код в окно ввода и нажать кнопку Применить, чтобы начать испытание. Некоторые из примеров кода для Elevator Saga приведены ниже, чтобы дать вам общее представление:

  • чтобы сообщить лифту о переходе на 1-й этаж: elevator.goToFloor(1);

  • чтобы остановить лифт, если он движется: elevator.stop();

  • чтобы получить номер этажа, на котором в настоящее время находится лифт: elevator.currentFloor();

  • и многие другие.

4. Vim Adventures

Если вы часто испытываете трудности с VIM, то Vim Adventures наверняка создан для вас!! Vim Adventures это онлайн-игра, которая позволяет вам изучать горячие клавиши VIM и другие известные концепции в увлекательной и интересной форме с помощью игровой среды, подобной Zelda. Эта игра упрощает изучение и понимание мощного текстового редактора Vim, который впоследствии поможет вам стать более эффективным программистом.

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

5. CodeCombat

CodeCombat в основном рекомендуется тем людям, которые имеют небольшой или даже нулевой опыт в программировании, поскольку игра не только помогает вам практиковать свои навыки, но и обеспечивает замечательный процесс обучения в формате игры. Вы можете изучить различные языки программирования, такие как Python, JavaScript, CoffeeScript, Lua и т. д., с помощью игры. Вам нужно будет написать код на любом из этих языков, чтобы сообщить персонажу, что ему нужно делать. Более того, игра начинается с простых головоломок и задач, а затем уровень сложности постепенно растёт. И, да, в игру также включены различные обучающие программы, позволяющие овладеть синтаксисом языка.

Кроме того, CodeCombat это проект с открытым исходным кодом, и вы можете не только учиться и играть, но и вносить вклад в исходный код, чтобы добавлять новые функции, исправлять ошибки и т. д., чтобы повысить уровень своего программирования. Что ещё нужно?

6. Flexbox Defense

Flexbox Defense действительно один из лучших способов укрепить свои знания и навыки CSS Flexbox! Это игра в жанре Tower Defense, в которой вам необходимо не дать приближающимся врагам пройти через вашу оборону, переместив башни на такое место, чтобы турели могли стрелять во вторгшихся врагов, прежде чем они пройдут через вас. Вам необходимо использовать свойство justify-content в контейнере для размещения ваших башен. Несколько наиболее распространённых значений, принимаемых свойством justify-content, следующие:

  • flex-start: группировать элементы в начале главной оси;

  • flex-end: группировать элементы в конце главной оси;

  • center: группировать элементы в центре;

  • space-around: равномерно распределить элементы по главной оси так, чтобы вокруг всех элементов было равное пространство.

Есть много других свойств CSS Flexbox, которые используются в игре, такие как align-items, flex-direction, order и некоторые другие.

7. Code Hunt

Ещё игра в списке, которая может помочь вам попрактиковаться и улучшить свои навыки программирования в игровой манере, это Code Hunt. Это игра по программированию от Microsoft Research. Игра основана на головоломках, которые вы должны изучить, используя данные подсказки и контрольные примеры. Сначала вам нужно определить шаблон, а затем написать решение. Code Hunt позволяет вам овладеть двумя известными языками Java и C #. Игра разработана таким образом, чтобы научить вас основам этих двух языков.

Поскольку Code Hunt принадлежит Microsoft, её предпочитают миллионы студентов (и даже профессионалов) во всём мире, и, если вы с нетерпением ждёте, чтобы укрепить свои навыки владения Java или C# более увлекательным способом, вы, безусловно, можете попробовать.

8. CheckIO

CheckIO это игра по программированию, которая позволяет вам улучшить свои навыки, особенно для двух языков Python и TypeScript . Игра рекомендуется как новичкам, так и опытным программистам для повышения уровня своих навыков, так как она предоставляет вам множество захватывающих задач различных уровней сложности. Каждый набор этих задач расположен на разных островах, и пользователям необходимо решить требуемую задачу или головоломку, чтобы перейти с одного острова на другой. Кроме того, обогащающее и поддерживающее сообщество CheckIO помогает вам делиться знаниями и опытом с разными блестящими умами по всему миру.

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

9. Screeps

А вот и ещё одна популярная игра по программированию для всех программистов Screeps! Это онлайн-стратегия в реальном времени, которая требует от вас хотя бы некоторых базовых знаний в области программирования. В этой игре вам нужно создать свою собственную колонию в определённом мире, доступном всем игрокам. А колония сможет добывать ресурсы, создавать юнитов и завоевывать территории. Более того, необходимо запрограммировать реакцию юнитов на события, и вы можете сделать это, используя язык программирования JavaScript .

Вам также необходимо знать, что написание скрипта для Screeps ничем не отличается от написания любого другого приложения JavaScript. И вы также можете разделить свои скрипты на модули с помощью синтаксиса Node.js, чтобы сделать игру более удобной.

Кроме того, вы можете использовать другие языки, такие как C++ и т. д., А также можете компилировать их с помощью WebAssembly. А также Screeps позволяет вам вносить свой вклад в разработку игрового движка и изменять поведение игровых объектов.

10. CSS Diner

Наконец, CSS Diner игра по программированию, которая помогает вам практиковаться и совершенствовать свои навыки CSS. Игра помогает вам управлять селекторами CSS на всех 32 уровнях, включённых в игру. И уровень сложности каждого раунда повышается по мере прохождения игры. Игра состоит из различных захватывающих уровней в зависимости от нескольких важных атрибутов, таких как id, classname, empty, first-child, only-of-type и многих других. Более того, если вам нужна подсказка для решения определённого уровня, всё, что вам нужно сделать, это навести указатель мыши на элементы в таблице и просмотреть HTML-разметку.

Игра предоставит вам лучшее понимание для выбора определённых элементов в HTML и CSS и впоследствии поможет вам перемещаться по элементам DOM, когда дело касается JavaScript. И самое приятное то, что вы можете играть в CSS Diner в своем браузере без каких-либо затрат или хлопот, таких как вход в систему, создание учётной записи и т. д.

Также можно принять во внимание несколько других игр: Codewars, SQL Murder Mystery и Duskers. Излишне говорить, что почти каждый технический энтузиаст так или иначе склонен к играм. А с помощью упомянутых выше игр по программированию вы можете улучшить свои навыки более увлекательным и авантюрным способом. Тем не менее вам не рекомендуется идти на компромисс с продолжающимся процессом обучения и использовать эти игры в течение ограниченного времени, поскольку избыток чего-либо всегда неблагоприятен.

Если у вас есть на примете полезные игровые проекты подобные этим, но в список не попавшие делитесь ими в комментариях!

Играми поделились, а теперь поделимся и релевантными программами обучения. Тем кому в освоении нового не хватает "крепкого плеча" ментора, которая поможет довести начатое до конца добро пожаловать на наши программы Fullstack-разработчик на Python, разработка на C# и разработка на Java и да прибудет с вами сила.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Как научиться думать три базовых момента

27.02.2021 20:23:19 | Автор: admin

Очевидно, что учат этому далеко не везде. Как минимум, делают акцент не на этом навыке, а на отдельных методах и дисциплинах. Хотя, для занятий последними, да и для принятия решений на работе и в быту, базовая ментальная гигиена точно не повредит. Поговорим о ней в нашем материале и обсудим матчасть, гибкую оптику и вспомогательные инструменты.

Фотография: Roman Bilik. Источник: Unsplash.comФотография: Roman Bilik. Источник: Unsplash.com

Знайте матчасть

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

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

Как говорит Билл Гейтс: чем больше изучаешь тему, тем крепче становится фундамент для новых знаний, плюс повышается связность уже имеющейся информации.

Знать и разбираться в когнитивных искажения [КИ] стоит еще и потому, что в запущенных ситуациях они могут приводить и к неприятным эффектам например, незаметно перестраивать наши воспоминания в угоду той или иной проблеме эмоционального или иного характера и дестабилизировать психику [подобными кейсами занимаются когнитивные психотерапевты].

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

Наиболее известными КИ являются эффект Даннинга Крюгера, иллюстрирующий неспособность низкоквалифицированных специалистов осознавать свои ошибки; проклятие знания близкое КИ, объясняющее, почему более информированные люди скорее всего не смогут точно прогнозировать действия менее информированных; и нога в двери, которым часто, но весьма неумело пользуются телефонные спамеры.

Фотография: Phil Desforges. Источник: Unsplash.comФотография: Phil Desforges. Источник: Unsplash.com

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

Матрица НАСА для оценки рисков в зависимости от возможных последствий и вероятности наступления событий; фреймворки GOFER и DECIDE, описывающие базовые алгоритмы для принятия решений; и реверс-инжиниринг вероятных проблем в формате pre-mortem одни из наиболее заметных примеров ментальных моделей.

Различайте грабли

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

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

Пользуйтесь простыми инструментами

Сложные часто ведут в сторону бесконечной настройки, установки обновлений и поиска информации, которой нужно заполнять календарики, борды и to-do-листы. В определенных случаях и в рамках конкретных проектов во всех этих действительно есть смысл, но если от усложнения инструментов для ведения заметок, организации дел и размышлений можно отказаться без потерь с точки зрения результатов, то стоит так и поступить. Иначе они перетянут внимание на себя. Есть даже похожее когнитивное искажение, связанное с поиском информации ради самого поиска, который обычно не дает видимого результата и не влияет на что-либо.

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

Фотография: strichpunkt. Источник: Pixabay Фотография: strichpunkt. Источник: Pixabay

Помимо тренажеров для изучения нового и укрепления памяти есть похожие карточные системы для развития творческого аспекта мышления и использования максимально простых ментальных моделей, способствующих креативу. Одна из таких систем называется Oblique Strategies. Ее разработали в начале 70-х художник Питер Шмидт и музыкант Брайан Ино.

Вышло более шести редакций карточек, некоторые в виде небольших партий со специальным оформлением. Но сегодня есть и веб-версии с генераторами случайных карт из этой серии и даже версия для голосового ассистента Alexa, плюс всевозможные аналоги вроде идей для стартапов и рекомендаций для предпринимателей. Что интересно, Oblique Strategies неоднократно упоминали в поп-культуре отсылки к ним есть в творчестве R.E.M., независимых фильмах и комиксах.

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

Среда условного Хабра, где вы можете наблюдать (1) мгновенную реакцию на ваши комментарии, (2) следить за успехами любимых авторов и делать это (3) на регулярной основе, является достаточной для развития не только мышления, но и прокачки интуиции понимания того, что в действительности волнует и беспокоит ваших коллег по профессии, да и по рунету в целом. Именно эти три условия описал Даниел Канеман, известный писатель, психолог и лауреат крупнейших премий по экономике, когда его попросили объяснить природу интуитивного мышления. Надеемся, что наш сегодняшний рассказ вдохновит вас на развитие, друзья!


Англоязычные материалы в нашем блоге на Хабре:

И русскоязычные хабрапосты по теме:


Подробнее..

Что и как учить, чтобы войти в IT

13.05.2021 10:08:31 | Автор: admin

Пока я спал, в одном из чатовшло активное обсуждение по ряду вопросов, на тему которых мне бы тоже хотелось высказаться. Боюсь, что в одно сообщение всё не влезет, посему оформлю отдельным постом. Итак, поехали.

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

Тут я могу ответить старым анекдотом

- Софочка, что Вы будете пить: спирт, водку или самогон?
- Ой, я даже не знаю, всё такое вкусное

Решения проблемы погони за стадом зайцев я вижу три:

  • первый метод прост до безобразия: вообще не напрягать себе голову какими-то целями, задачами, планами, сроками и прочими атрибутами взрослой разработки. А разбираться с тем, что интересно конкретно в данный момент. Интересно потрогать Spring трогаем, научиться сводить конфликты в Git учимся, освоить употребление перфектных времён в амереконском языке осваиваем. Надоело отложили на полку и вернулись когда-нибудь, когда эта тема снова стала актуальна в плане интереса. И не могу сказать, что данный метод совсем уж бесполезный. Т.к. изучение чего бы то ни было будет подпитываться живым интересом, то сил на это будет затрачиваться меньше, чем в режиме надо, а через это усвояемость материала может оказаться лучше. И пусть получается набор знаний, часто поверхностных, из разных областей, но рано или поздно приходит навык комбинирования этих знаний для создания чего-то нового. Из минусов данного подхода могу отметить опасность превращения в ламера сверхширокого профиля, когда знаешь много всего разного, но по чуть-чуть. Ещё одна опасность кроется в том, что областей знания, которые интересны, становится слишком много и мы опять возвращаемся к исходной проблеме что пить.

  • второй метод коротко можно охарактеризовать так: полковник со шрамом поставил задачу. Т.е. делаем только то, что актуально в данный момент. Нужно научиться клонировать Git-репозитории учимся клонировать и ничего более, нужно перевести приложение с самописного решения на Spring берём и делаем, нужно написать письмо/багрепорт/комментарий на амереконском языке коллегам и при этом не выглядеть полным идиотом в плане грамматики/орфографии изыскиваем способы. Метод хорош тем, что постановка задач идёт из вне и есть некоторая ненулевая вероятность, что эта постановка будет целостной и приведёт к какому-то понятному конечному результату. Недостатков у данного метода тоже хватает. Это и опасность неправильной постановки задач, и неспособность самостоятельно ставить себе цели и достигать их, всегда будет нужен кто-то, кто возьмёт тебя за поводок и поведёт куда-то, и несовпадение конечного результата с тем, чего хотелось достичь изначально, ибо задачи ставились кем-то ещё, и этот кто-то в первую очередь преследовал свои собственные цели.

  • на мой взгляд самый действенный метод состоит в объединении первого и второго подходов. Т.е. мы либо сами, исходя из своих интересов, выбираем себе цель, но кто-то другой определяет для нас используемые инструменты и/или способы её достижения. Или наоборот, кто-то указывает нам цель, а как до неё добраться выбираем мы сами. Плюсом является то, что с одной стороны не теряется тот самый живой интерес, который будет поддерживать нас в освоении новых навыков, с другой стороны у нас сохраняется концентрация на каком-то наборе знаний/навыков, который необходимо получить. К сожалению, недостатки объединяемых методов тоже никуда не деваются, но, к счастью, их влияние на нас сглаживается, т.к. попасть в ситуацию, когда вот ваще абсолютно всё пошло не так это надо обладать каким-то запредельным уровнем невезения. Хотя в своей практике я встречал подобное.

Посоветовать какой-то один метод освоения нового яне могу, они все рабочие только комбинация всех трёх даёт оптимальный результат. Внешние ограничители не дают распыляться и позволяют сохранить концентрацию на задаче, свобода выбора и наличие живого интереса позволяют закончить начатое и не выгореть в процессе. Так же можно в 100500 упомянуть про постановку целей по SMART. Для чего мы хотим освоить тот или иной навык? Просто развлечься, стоит задача на работе или мы хотим освоить новую профессию и выйти на другой уровень дохода? От ответа на этот важный вопрос и будут зависеть и сроки, и вовлечённость, и сколько времени и сил мы будем готовы потратить на получение новых знаний.

Как себя заставить?

Другой важный вопрос, который подняли в той же дискуссии: Как себя заставить/мотивировать изучать что-то? На мой взгляд решение имеющихся задач/достижение поставленных целей уже являются достаточными мотиваторами для освоения чего-то нового. При этом даже банального мне интересно бывает достаточно, хоть и не всегда. Попробую пояснить на примерах:

  1. TeamCity Kotlin DSL. Эта технология жизненно необходима мне в работе, без неё я не смогу выполнять свои обязанности. Поэтому мне в самом начале минимально пришлось освоить Kotlin и основной набор выразительных средств TeamCity DSL, чтобы просто начать что-то делать. Сейчас же я стараюсь по мере необходимости и при наличии возможности углублять свои знания в этих областях, т.к. это позволяет мне быть эффективнее.

  2. Kubernetes/Helm. В теории эти технологии тоже должны быть для меня жизненно необходимы, но ими занимается мой коллега и я почти их не касаюсь. Поэтому для меня достаточно весьма поверхностного понимая как и что там работает. И нет мотивации погружаться в эти технологии глубже.

  3. Авария на Чернобыльской АЭС. Это как раз тот случай, когда мне просто интересно. Причём интересны мне скорее технические аспекты данного события: устройство реактора, его недостатки, возникновение и течение аварии, способы ликвидации и т.д. Поэтому, когда попадаются новые статьи на эту тему, то я выделяю время на их прочтение. Я не исключаю, что в какой-то момент я удовлетворю своё любопытство и потеряю к данной теме интерес.

  4. Vim. Вроде бы было бы неплохо бы его освоить. И когда-то это даже было интересно, но сейчас я использую совершенно другой набор ПО и такой необходимости нет. А если не видно разницы

Как можно видеть из примеров выше, ни в одном из случаев я не заставляю себя осваивать что-то. Либо для этого существует вполне понятная мотивация, и получение новых знаний оправдано. Либо такой мотивации нет и смысл тогда напрягаться? Ещё хотелось бы вскользь упомянуть такое явление как навязанные цели. Т.к. я работаю DevOps-инженером, то считается, что я должен хорошо знать Kubernetes. Вот только реальной потребности в глубоких знаниях по данной теме у меня на данный момент нет и без особой необходимости я их получать не намерен, ибо это будет пустой тратой времени. Важно вовремя замечать такие навязанные цели и не поддаваться их влиянию.

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

Подробнее..

Перевод Почему я перестал читать статьи Как стать разработчиком

13.03.2021 16:07:18 | Автор: admin
Совет для начинающих разработчиков

image


Я бы хотел, чтобы во времена, когда я учился программированию, кто-то сказал мне перестать читать статьи о том, Как стать разработчиком за X месяцев. Так что позвольте мне донести эту мысль до вас.

Перестаньте читать эти чертовы статьи.

Понимаю, некоторые люди будут сопротивляться этому заявлению (особенно авторы таких статей). Для начала отмечу, что это исключительно мое мнение. Если вы любите читать такие статьи, не давайте мне остановить вас.

Но если вы начинающий разработчик, вам лучше игнорировать такие статьи (или хотя бы относиться к ним с большим недоверием).

Позвольте объяснить почему.

Если мне удалось сделать это быстро, то и у вас получится!


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

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

Я узнал ответ на этот вопрос на горьком опыте. Когда я учился программировать, я начинал с самого дна. У меня не было никакого опыта. Ни HTML, ни CSS. Я даже не редактировал свою страницу на MySpace.

У меня была бесперспективная работа, а я хотел построить карьеру с потенциалом для роста. Я читал исследования, в которых говорилось, что программисты обычно удовлетворены своей работой и имеют хорошие зарплаты. Это и стало катализатором, который призвал начать поиск вакансий разработчиков.

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

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

  • Как я научился программировать за 6 месяцев и попал в Google
  • Как я стал разработчиком-самоучкой за 7 месяцев. Вы тоже сможете
  • Как я прошел путь от новичка до инженера-программиста за 9 месяцев, работая полный рабочий день


Я поглощал эти статьи пачками, потому что они давали то, что мне было нужно: надежду.

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

image

У меня нет высшего образования в сфере Computer Sciene
116 дней самообразования
12 недель курсов
и очень много энтузиазма
Если мне удалось, то и вы сможете


Реальность быстро внесла коррективы в эту картину. Если вы не знали: 6 месяцев это совсем немного. Прежде чем я об этом узнал, я как раз был на шестом месяце учебы, и мне было особо нечего показать. Да, я уже знал основы HTML, CSS и JavaScript, и я мог создать статический сайт. Но к работе я был вовсе не готов.

Все эти статьи в духе Как я получил свою первую работу разработчиком за 6 месяцев, которые когда-то меня утешали, стали моим кошмаром. Чем больше проходило времени, тем сильнее они меня угнетали. Прошел год, а мои попытки устроиться на работы проходили незамеченными. Я перестал думать Если они смогли, то и я смогу. Теперь я думал Как они это сделали? Я вообще способен на это?. Я больше не был похож на героев этих успешных историй.

Только когда я решил перестать читать эти статьи, мое настроение начало подниматься. Как бы ни было заманчиво сравнивать себя со своими сверстниками, я все это отпустил и сосредоточился на своем пути.

Хоть на это и потребовалось какое-то время, я вышел из крысиных бегов. И я смог поразмышлять о своем собственном путешествии и узнать некоторые важные истины.

Я не единственный, кто так себя чувствовал


Несмотря на то, что я сосредоточен на собственном опыте, так себя чувствовал не только я. С каждым годом в сферу технологий входит все больше и больше людей. Я часто общаюсь с новыми разработчиками, и их мнения по поводу статей такого типа перекликаются с моим собственным.

image

Спасибо что написал это, друг! Я был одним из тех, кто читал эти статьи и был несчастен. По мере того, как я встречаюсь с честными людьми вроде тебя, готовых принять неприятную часть этого пути, я нахожу в себе силы тоже ее принять.

Вот что я обычно говорю таким людям.

Эти статьи не отражают реальность для большинства

Простая истина заключается в том, что большинство начинающих разработчиков не находят работу в течение 6 или даже 12 месяцев. Многие профессиональные разработчики имеют высшее образование в этой области, на его получение уходит порядка 4 лет. Даже если мы отбросим колледж и рассмотрим только курсы, лишь небольшой процент их выпускников найдет работу в течение года.

Если мы взглянем на данные о приеме на работу от Fullstack Academy, известного и уважаемого образовательного заведения из Нью-Йорка, то мы увидим, что 52% выпускников нашли работу через 6 месяце после завершения курсов в 2019 году. Но если мы взглянем на людей, которых наняли в штат разработчиками ПО, то их доля составляет всего около 35%.

image

Сама программа рассчитана на 17 недель (13-недельный учебный план с четырьмя неделями подготовки). Мы можем предположить, что все участники что-то изучали перед тем, как прийти на эти курсы (от пары недель до пары месяцев). Это значит, что примерно треть людей, посещавших Fullstack Academy, найдут работу в течение года с момента начала обучения программированию.

Эти результаты характерны не только для Fullstack Academy. Вы можете посмотреть данные о приеме на работу после различных курсов и сравнить самостоятельно.

Честно говоря, с учетом всех обстоятельств, это неплохие результаты. Но если сравнить эту небольшую группу со всем пластом начинающих разработчиков (студентами, прошедшими курсы и самоучками), это небольшой кусочек.

Реальность такова, что если вы подумываете о том, чтобы начать карьеру в сфере технологий, для этого, скорее всего, потребуется как минимум год обучения. Мне потребовалось более двух лет, чтобы наконец получить свою первую работу. И в этом нет ничего плохого.

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

Вы не можете управлять временем


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

Установите себе дедлайн длительностью в один год. Когда он наступит, вам следует начать пытаться устроиться на работу.


Это ужасный и вредный совет.

Вы не можете скорость своего обучения и время на поиск первой работы. Постановка дедлайна может мотивировать, но она не заставит ваш мозг понимать JavaScript быстрее. Согласно закону Хофштадтера, когда вы устанавливаете для себя дедлайн, вы неизбежно отстаете от него. Обучение длится ровно столько, сколько нужно.

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

image

В среднем, я сидел в кафе от 8 до 12 часов.

Настоящая проверка, я уже много месяцев работаю в тяжелом темпе, я изучаю программирование больше 50 часов в неделю. Я буквально рискую всем, чтобы найти работу в одном из самых дорогих и конкурентных городов в США.

Между SSP и интенсивом Hack Reactor я провел 4 месяца, программируя 6 дней в неделю более 12 часов каждый день. Я отточил свои навыки решения задач, улучшил понимание JavaScript, изучил фреймворки для фронтенда и бэкенда, а также научился совместной работе.

* Подъем в 7 утра. Иду в спортзал.

* Час хожу по беговой дорожке, смотрю лекции по программированию и доклады по JavaScript.

* Сажусь на поезд и еду на работу, в поезде читаю твиттеры многих лидеров мнений по JavaScript и задаю им вопросы.

* Прихожу на работу в 9 утра, ухожу в 17. Честно говоря, иногда я курил травку, когда приходил домой.

* Учусь и программирую с 6 вечера до 3 утра

* Повторить сначала


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

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

  1. Опыт программирования
  2. Высшее образование
  3. Близость к технологическому хабу
  4. Наставники и помощники
  5. Подписки в социальных сетях
  6. Умение вести себя во время интервью и при общении


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

image


К сожалению, немногие из этих статей признают преимущества автора, заставляя вас поверить, что все, что вам нужно, это торопиться, торопиться и торопиться.

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

Заключение


Нет ничего плохого в том, чтобы писать статьи вроде Как я стал разработчиком программного обеспечения. Я сам их писал, так что понимаю, почему люди их пишут.

Вход в сферу программного обеспечения феноменальное достижение, которое следует отметить и задокументировать. Это катарсис писать и размышлять о своем опыте. Кроме того, такие статьи пользуются большой популярностью. Они получают клики и просмотры. Люди никогда не перестанут их писать. И они не должны.

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

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

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

Python, наука о данных и выборы часть 1

05.05.2021 20:22:59 | Автор: admin

Серия из 5 постов для начинающих представляет собой ремикс первой главы книги 2015 года под названием Clojure для науки о данных (Clojure for Data Science). Автор книги, Генри Гарнер, любезно дал согласие на использование материалов книги для данного ремикса с использованием языка Python.

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

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

Несправедливо, когда превосходный учебный материал пылится невостребованным просто из-за того, что имплементирован на достаточно академичном, если не сказать элитарном языке, каким является язык функционального программирования Clojure. Поэтому возникло желание внести свои пять копеек, чтобы сделать материал книги доступным для более широкой публики.

Три главы книги были адаптированы под язык Python в течение следующего года после издания книги, т.е. в 2016 году. Публикация ремикса книги в РФ не получилась по разным причинам, но главная из них станет понятной в конце этой серии постов. В конце заключительного поста можно будет проголосовать за или против размещения следующей серии постов. А пока же

Пост 1 посвящен подготовке среды и данных.

Статистика

Важно не кто голосует, а кто подсчитывает голоса

Иосиф Сталин

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

При изучении распределений чрезвычайную важность играет наглядная и удобная визуализация данных, и для этого мы воспользуемся Python-овской библиотекой pandas. Мы покажем, как пользоваться ею для загрузки, преобразования и разведывательного анализа реальных данных, а также начнем работать с фундаментальной библиотекой numpy для научных вычислений. Мы проведем сопоставительный анализ результатов двух общенациональных выборов всеобщих выборов в Великобритании 2010 г. и российских выборов депутатов Государственной Думы Федерального Собрания РФ шестого созыва 2011 г. и увидим, каким образом даже элементарный анализ может предъявить подтверждающие данные о потенциальных фальсификациях.

Примеры исходного кода для этого поста находится в моем репо на Github.

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

Кроме того, мы будем пользоваться встроенными в Python модулями. Так, например, модуль random позволяет генерировать случайные числа и извлекать выборки, и модуль collections содержит дополнительные структуры данных, из которых мы воспользуемся специальным словарем Counter.

В основе библиотеки pandas лежит понятие кадра данных, DataFrame, т.е. структуры, состоящей из строк и столбцов, или записей и полей. Если у вас есть опыт работы с реляционными базами данных, то таблицы pandas можно представить, как таблицы базы данных. Каждый столбец в кадре данных поименован, а каждая строка имеет одинаковое число столбцов, как и любая другая. Загрузить данные в кадр данных pandas можно несколькими способами, и тот, которым мы воспользуемся, будет зависеть от того, в каком виде наши данные хранятся:

  • Если данные представлены текстовым файлом с разделением полей данных запятыми (.csv) или символами табуляции (.tsv), то мы будем использовать функцию чтения данных read_csv

  • Если данные представлены файлом Excel (например, файл .xls или .xlsx), то мы воспользуемся функцией чтения данных read_excel

  • Для любого другого источника данных (внешняя база данных, веб-сайт, буфер обмена данными, JSON-файлы, HTML-файлы и т. д.) предусмотрен ряд других функций

Помимо кадров данных мы будем пользоваться еще одной популярной структурой Series, т.е. рядом данных. Это одномерный массив данных, необязательно числовых, которую мы тоже будем использовать.

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

pd.read_excel('data/ch01/UK2010.xls')

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

def load_uk(): '''Загрузить данные по Великобритании''' return pd.read_excel('data/ch01/UK2010.xls') 

Эта функция вернет кадр данных DataFrame библиотеки pandas, содержащий данные по Великобритании. Далее в этой главе, мы определим дополнительные имплементации загрузки этого же и еще одного набора данных.

Первая строка электронной таблицы UK2010.xls содержит имена столбцов. Функция библиотеки pandas read_excel резервирует их в качестве имен столбцов возвращаемого кадра данных. Начнем обследование данных с их проверки атрибут кадра данных columns возвращает имена столбцов в виде списка, при этом адресация атрибутов осуществляется при помощи оператора точки (.):

def ex_1_1(): '''Получить имена полей кадра данных''' return load_uk().columns

Результатом выполнения приведенной выше функции должен быть следующий ниже список полей кадра данных pandas:

Index(['Press Association Reference', 'Constituency Name', 'Region', 'Election Year', 'Electorate', 'Votes', 'AC', 'AD', 'AGS', 'APNI', ... 'UKIP', 'UPS', 'UV', 'VCCA', 'Vote', 'Wessex Reg', 'WRP', 'You', 'Youth', 'YRDPL'], dtype='object', length=144)

Это очень широкий набор данных, состоящий из 144 полей. Первые шесть столбцов в файле данных описываются следующим образом; последующие столбцы лишь распределяют число голосов по партиям:

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

  • Название избирательного округа: стандартное название, данное избирательному округу

  • Регион: географический район Великобритании, где округ расположен

  • Год выборов: год, в котором выборы состоялись

  • Электорат: общее число граждан, имеющих право голоса в избирательном округе

  • Голосование: общее число проголосовавших

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

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

def ex_1_2(): '''Получить значения поля "Год выборов"''' return load_uk()['Election Year']

В результате будет выведен следующий список:

0 2010.01 2010.02 2010.0...646 2010.0647 2010.0648 2010.0649 2010.0650 NaNName: Election Year, dtype: float64

Столбец года выборов возвращается в виде последовательности значений. Полученный результат бывает трудно интерпретировать, поскольку кадр данных содержит слишком много строк. Учитывая, что мы хотели бы узнать, какие уникальные значения есть в этом столбце, можно воспользоваться методом unique кадра данных. Одно из преимуществ использования библиотеки pandas состоит в том, что ее утилитные функции управления данными дополняют те, которые уже встроены в Python. Следующий ниже пример это показывает:

def ex_1_3(): '''Получить значения в поле "Год выборов" без дубликатов''' return load_uk()['Election Year'].unique()
[ 2010. nan]

Значение 2010 еще больше подкрепляет наши ожидания в отношении того, что эти данные относятся к 2010 году. Впрочем, наличие специального значения nan, от англ. not a number, т.е. не число, которое сигнализирует о пропущенных данных, является неожиданным и может свидетельствовать о проблеме с данными.

Мы еще не знаем, в скольких элементах набора данных пропущены значения, и установив их число, мы смогли бы решить, что делать дальше. Простой способ подсчитать такие пустые элементы состоит в использовании подкласса словарей Counter языка Python из модуля collections. Этот словарь трансформирует последовательность значений в коллекцию, где ключам поставлены в соответствие количества появлений элементов данных, т.е. их частоты:

def ex_1_4(): '''Рассчитать частоты в поле "Год выборов"  (количества появлений разных значений)''' return Counter( load_uk()['Election Year'] )
Counter({nan: 1, 2010.0: 650})

Нам не потребуется много времени, чтобы получить подтверждение, что в 2010 г. в Великобритании было 650 избирательных округов. Знание предметной области, как в этом случае, имеет неоценимое значение при проверке достоверности новых данных. Таким образом, весьма вероятно, что значение nan является посторонним, и его можно удалить. Мы увидим, как это сделать, в следующем разделе.

Исправление данных

Согласно неоднократно подтвержденной статистике, как минимум 80% рабочего времени исследователь данных тратит на исправление данных. Эта процедура заключается в выявлении потенциально поврежденных или некорректных данных и их корректировке либо фильтрации.

Специальное значение nan в конце столбца года выборов может сигнализировать о грязных данных, которые требуется удалить. Мы уже убедились, что нужные столбцы данных в pandas можно отобрать, указав их номера или имена. Для фильтрации записей данных можно воспользоваться одним из предикативных методов библиотеки pandas.

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

def ex_1_5(): '''Вернуть отфильтрованную по полю "Год выборов"  запись в кадре данных (в виде словаря)''' df = load_uk() return df[ df['Election Year'].isnull() ]

Press Association Reference

Constituency Name

Region

Election Year

Electorate

Votes

AC

AD

AGS

...

650

NaN

NaN

NaN

NaN

NaN

29687604

NaN

NaN

NaN

...

Выражение dt['Election Year'].isnull() вернет булеву последовательность, в которой все элементы, кроме последнего, равны False, в результате чего будет возвращена последняя запись кадра данных. Если Вы знаете язык запросов SQL, то отметите, что этот метод очень похож на условный оператор WHERE.

Присмотревшись к результатам примера ex_1_5, можно заметить, что в полученной записи все поля (кроме одного) имеют значение NaN. Дальнейший анализ данных подтверждает, что строка с непустым полем на самом деле является строкой итоговой суммы в листе файла Excel. Эту строку следует из набора данных удалить. Мы можем удалять проблемные строки путем обновления коллекции предикативной функцией notnull(), которая в данном случае вернет только те строки, в которых год выборов не равен NaN:

 df = load_uk() return df[ df[ 'Election Year' ].notnull() ]

Приведенные выше строки нам почти всегда придется вызывать непосредственно перед использованием данных. Лучше всего это сделать, добавив еще одну имплементацию функции загрузки данных по Великобритании load_uk_scrubbed с этим этапом фильтрации:

def load_uk_scrubbed(): '''Загрузить и отфильтровать данные по Великобритании''' df = load_uk() return df[ df[ 'Election Year' ].notnull() ]

Теперь при написании любого фрагмента кода с описанием доступа к набору данных в файле, можно выбирать вариант загрузки: обычный при помощи функции load_uk либо его аналог с очисткой данных load_uk_scrubbed. Приведенный выше пример должен вернуть список из 650 чисел, обозначающих количество избирателей в каждом избирательном округе Великобритании.

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

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

Подробнее..

Python, наука о данных и выборы часть 4

06.05.2021 08:19:11 | Автор: admin

Пост 4 для начинающих посвящен техническим приемам визуализации данных.

Важность визуализации

Простые приемы визуализации, подобные тем, которые были показаны ранее, позволяют лаконично передать большое количество информации. Они дополняют сводные статистики, которые мы рассчитали ранее в этой главе, и поэтому очень важно уметь ими пользоваться. Такие статистики, как среднее значение и стандартное отклонение, неизбежно скрывают много информации по той причине, что сворачивают последовательность в одно единственное число.

Английский математик Фрэнсис Энскомб составил коллекцию из четырех точечных графиков, ныне известную как квартет Энскомба, которые обладают практически идентичными статистическими свойствами (включая среднее, дисперсию и стандартное отклонение). Несмотря на это, они четко показывают, что распределение значений последовательностей и сильно расходится:

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

Способности учащихся вполне ожидаемо должны быть нормально распределены, и действительно за исключением крутого всплеска вокруг 30% так и есть. То, что мы ясно наблюдаем это результат по-человечески понятного натягивания экзаменаторами оценок учащегося на проходной балл.

На самом деле статистические распределения для последовательностей, взятых из крупных выборок, могут быть настолько надежными, что даже незначительное отклонение от них может являться свидетельством противоправной деятельности. Закон Бенфорда, или закон первой цифры, показывает любопытную особенность случайных чисел, которые генерируются в широком диапазоне. Единица появляется в качестве ведущей цифры примерно в 30% случаев, в то время как цифры крупнее появляется все реже и реже. Например, девятка появляется в виде первой цифры менее чем в 5% случаев.

Закон Бенфорда назван в честь физика Фрэнка Бенфорда (Frank Benford), который сформулировал его в 1938 г., показав его состоятельность на различных источниках данных. Проявление этого закона было ранее отмечено американским астрономом Саймоном Ньюкомом (Simon Newcomb), который еще более 50 лет назад до него обратил внимание на страницы своих логарифмических справочников: страницы с номерами, начинавшихся с цифры 1, имели более потрепанный вид.

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

Визуализация данных об электорате

Вернемся к данным выборов и сравним электоральную последовательность, которую мы создали ранее, относительно теоретической нормальной ИФР. Для создания нормальной ИФР из последовательности значений можно воспользоваться функцией sp.random.normal библиотеки SciPy, как уже было показано выше. Среднее значение и стандартное отклонение по умолчанию равны соответственно 0 и 1, поэтому нам нужно предоставить измеренные среднее значение и стандартное отклонение, взятые из электоральных данных. Эти значения для наших электоральных данных составляют соответственно 70150 и 7679.

Ранее в этой главе мы уже генерировали эмпирическую ИФР. Следующий ниже пример просто сгенерирует обе ИФР и выведет их на одном двумерном графике:

def ex_1_24(): '''Показать эмпирическую и подогнанную ИФР  электората Великобритании''' emp = load_uk_scrubbed()['Electorate'] fitted = stats.norm.rvs(emp.mean(), emp.std(ddof=0), len(emp)) df = empirical_cdf(emp) df2 = empirical_cdf(fitted) ax = df.plot(0, 1, label='эмпирическая')  df2.plot(0, 1, label='подогнанная', grid=True, ax=ax)  plt.xlabel('Электорат') plt.ylabel('Вероятность') plt.legend(loc='best') plt.show()

Приведенный выше пример создаст следующий график:

Несмотря на наличие незначительной асимметрии, близкая расположенность двух кривых друг к другу говорит о нормальности исходных данных. Асимметрия выражена в противоположном направлении относительно построенной ранее кривой ИФР нечестного булочника, то есть наши данные об электорате слегка смещены влево.

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

def ex_1_25(): '''Показать квантильный график  электората Великобритании''' qqplot( load_uk_scrubbed()['Electorate'] ) plt.show()

Следующий ниже квантильный график еще лучше показывает левую асимметрию, с очевидностью присутствующую в данных:

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

Добавление производных столбцов

В целях выяснения процента электората, который проголосовал за одну из двух партий, требуется вычислить сумму голосов, отданных за каждую из них. Для этого нам понадобится создать новое поле данных Victors (Победители) из данных, которые соответствуют Консервативной (Con) и Либерально-демократической (LD) партиям и заодно проверим, имеются ли пропущенные значения.

def ex_1_26(): '''Вычислить производное поле данных "Победители" и  число имеющихся в нем пропущенных значений''' df = load_uk_scrubbed() df['Победители'] = df['Con'] + df['LD'] freq = Counter(df['Con'].apply( lambda x: x > 0 )) print('Поле "Победители": %d, в т.ч. пропущено %d'  % (freq[True], freq[False]))
Поле "Победители": 631, в т.ч. пропущено 19

Результат показывает, что в 19 случаях данные отсутствуют. Очевидно, что в каком-то из столбцов: столбце Con либо столбце LD (либо обоих), данные отсутствуют, но в каком именно? Снова воспользуемся словарем Counter, чтобы увидеть масштаб проблемы:

'''Проверить пропущенные значения в полях "Консервативная партия" (Con) и   "Либерально-демократическая партия" (LD)'''df = load_uk_scrubbed()Counter(df['Con'].apply(lambda x: x > 0)),  Counter(df['LD'].apply(lambda x: x > 0))
(Counter({False: 19, True: 631}), Counter({False: 19, True: 631}))

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

def ex_1_27(): '''Выборка полей данных по условию, что поля "Консервативная партия" (Con) и  "Либерально-демократическая" (LD) не пустые''' df = load_uk_scrubbed() rule = df['Con'].isnull() & df['LD'].isnull() return df[rule][['Region', 'Electorate', 'Con', 'LD']]

Region

Electorate

Con

LD

12

Northern Ireland

60204.0

NaN

NaN

13

Northern Ireland

73338.0

NaN

NaN

14

Northern Ireland

63054.0

NaN

NaN

584

Northern Ireland

64594.0

NaN

NaN

585

Northern Ireland

74732.0

NaN

NaN

Небольшое обследование данных должно определить причину, почему эти поля оказались пустыми. Как оказалось, кандидаты в соответствующих избирательных округах не выдвигались. Следует ли эти строки отфильтровать или же оставить как есть, равными нулю? Это интересный вопрос. Давайте их отфильтруем, поскольку вообще-то невозможно, чтобы в этих округах избиратели выбрали какого-либо кандидата, неважно от либеральных демократов или консерваторов. Если же мы напротив допустили, что они равны нулю, то среднее количество людей, которое при заданных вариантах выбора проголосовало за одну из этих партий, было бы искусственно занижено.

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

def load_uk_victors(): '''Загрузить данные по Великобритании,  выбрать поля и отфильтровать''' df = load_uk_scrubbed() rule = df['Con'].notnull() df = df[rule][['Con', 'LD', 'Votes', 'Electorate']]  df['Победители'] = df['Con'] + df['LD']  df['Доля победителей'] = df['Победители'] / df['Votes']  df['Явка'] = df['Votes'] / df['Electorate'] return df

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

def ex_1_28(): '''Показать квантильный график победителей  на выборах в Великобритании''' qqplot( load_uk_victors()['Доля победителей'] ) plt.show()

Приведенный выше пример создаст следующий ниже график:

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

Примеры исходного кода для этого поста находится в моем репо на Github.

Следующая заключительная часть, часть 5, серии постов Python, наука о данных и выборы посвящена сопоставительной визуализации электоральных данных.

Подробнее..

ФП на Python посредством Coconut! gt print

10.05.2021 10:05:19 | Автор: admin

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

"Здравствуй, Coconut!" |> print

Язык Coconut (на момент написания поста его последней версией является v1.5.0) - это функционально-ориентированное строгое надмножество языка Python, и поэтому все, что валидно для Python, также валидно для Coconut, при этом Coconut транспилируется в Python. По сути Coconut представляет собой игровую площадку для освоения парадигмы функционального программирования, тестирования идей в области ФП, отработки приемов решения задач в указанной парадигме и для учебных целей.

На странице веб-сайта языка утверждается, что язык Coconut создан быть вам полезным. Coconut расширяет репертуар программистов на Python, задействуя инструменты современного функционального программирования, упрощая использование этих инструментов и усиливая их мощность. Иными словами, язык Coconut делает с функциональным программированием то, что язык Python сделал с императивным программированием.

Будем надеяться, что этот пост докажет эти утверждения на практике.

На всякий случай, установить Coconut можно посредством менеджера пакетов pip: pip install coconut

Coconut - это строгое надмножество языка Python

Написание кода Python в функциональном стиле нередко выливается в сложную задачу, начиная от незначительных неудобств, таких как многословный синтаксис лямбд, и заканчивая более серьезными проблемами, такими как связывание в цепочку лениво вычисляемых итераторов и сопоставление с шаблонами. Coconut - это функциональное надмножество языка Python, целью которого является создание элегантного и функционально-ориентированного кода в стиле Python.

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

Разработанный в 2016 году диалект Python с открытым исходным кодом обеспечивает синтаксис для использования функций, которые можно найти в функционально-ориентированных языках, таких как Haskell и Scala. Многие функции Coconut включают в себя более элегантные и читаемые способы выполнения того, что уже делает Python. Например, программирование в стиле конвейера позволяет передавать аргументы функции в функцию с помощью отдельного синтаксиса. Например, print("Здравствуй, мир!") можно написать как "Здравствуй, мир!" |> print. Лямбды, или анонимные функции в Python, могут писаться четче, например (x) -> x2 вместо lambda x: x2.

Вот неполный перечень того, что предлагает Coconut:

  • Сопоставление с шаблонами

  • Алгебраические типы данных

  • Деструктурирующее присваивание

  • Частичное применение функций

  • Ленивые списки

  • Функциональная композиция

  • Более удобные лямбды

  • Инфиксная нотация

  • Конвейерное программирование

  • Операторные функции

  • Оптимизация хвостовых вызовов

  • Параллельное программирование

В настоящее время версия coconut-develop (pip install coconut-develop) имеет полную поддержку синтаксиса и поведения сопоставления с шаблонами Python 3.10, а также полную обратную совместимость с предыдущими версиями Coconut. Эта поддержка будет выпущена в следующей версии Coconut v1.6.0.

Coconut обрабатывает различия между принятым в Python и Coconut поведением сопоставления с шаблонами следующим образом:

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

Компиляции исходного кода coconut во что-то другое, кроме исходного кода Python, в планах не стоит. Исходник на Python является единственной возможной целью транспиляции для Coconut, которая поддерживает возможность создания универсального кода, работающего одинаково на всех версиях Python такое поведение невозможно с байт-кодом Python.

Далее, мы определим различные болевые точки при написании функционального кода на Python и продемонстрируем, как Coconut решает эти проблемы. В частности, мы начнем с базовой задачи программирования и перейдем к разработке конвейера ML с помощью функционального подхода.

Задача о решете Эратосфена

Решето Эратосфена (Sieve of Eratosthenes) - это алгоритм нахождения всех простых чисел до некоторого целого числа n, который приписывают древнегреческому математику Эратосфену Киренскому. Как и во многих случаях, здесь название алгоритма говорит о принципе его работы, то есть решето подразумевает фильтрацию, в данном случае фильтрацию всех чисел за исключением простых. По мере прохождения списка нужные числа остаются, а ненужные (они называются составными) исключаются.

Решение задачи средствами Python

Решение задачи о решете Эратосфена на чистом Python состоит из двух функций: primes и sieve. Функция primes вызывает внутреннюю функцию sieve.

from itertools import count, takewhiledef primes():    def sieve(numbers):        head = next(numbers)        yield head        yield from sieve(n for n in numbers if n % head)    return sieve(count(2))list(takewhile(lambda x: x < 60, primes()))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59]

При вызове функции sieve мы создаем генератор count, генерирующий целые числа, начиная с 2 и до бесконечности. В теле функции sieve мы берем головной элемент списка и выдаем его (yield) в качестве результата. В следующей строке кода мы выдаем результат (yield from) рекурсивного вызова функции sieve, которая в своем аргументе поочередно выбирает число по условию.

Обратите внимание, что numbers в выражении next(numbers) отличается от numbers в выражении n for n in numbers if n % head. Вся причина в том, что функция next - это операция с поддержкой состояния: взяв головной элемент списка, у вас останется хвост списка.

В последней инструкции использована функция list, поскольку takewhile производит генератор, и без list не получится заглянуть вовнутрь списка.

Таким образом, мы имеем довольно-таки императивный код: сделать это, сделать то и т.д.

Пошаговая замена кода Python на код Coconut

Всего за 7 шагов и легким движением руки(с) мы преобразуем чистый код Python в чистый функциональный код Coconut.

1. Убрать lambda

Замена ключевого слова lambda оформляется как комбинация символов ->.

from itertools import count, takewhiledef primes():    def sieve(numbers):        head = next(numbers)        yield head        yield from sieve(n for n in numbers if n % head)    return sieve(count(2))list(takewhile(x -> x < 60, primes()))

2. Ввести прямой конвейер

Прямой конвейер переставляет обычный порядок приложения функций f(g(h(d))) на вперед-направленный: d -> h -> g -> f и оформляется через комбинацию символов |>.

from itertools import count, takewhiledef primes():    def sieve(numbers):        head = next(numbers)        yield head        yield from sieve(n for n in numbers if n % head)    return sieve(count(2))primes() |> ns -> takewhile(x -> x < 60, ns) |> list

3. Ввести каррирование

Каррирование, или карринг, - это в сущности частичное приложение функции. Каррирование оформляется через символ $.

from itertools import count, takewhiledef primes():    def sieve(numbers):        head = next(numbers)        yield head        yield from sieve(n for n in numbers if n % head)    return sieve(count(2))primes() |> takewhile$(x -> x < 60) |> list

4. Ввести итераторную цепочку

По сути дела, применяя yield, вы говорите языку создать итератор из некого элемента в инструкции yield и из всего остального в инструкции yield from. И такое построение представляет собой итераторную цепочку, которая оформляется через комбинацию символов ::.

from itertools import count, takewhiledef primes():    def sieve(numbers):        head = next(numbers)        return [head] :: sieve(n for n in numbers if n % head)    return sieve(count(2))primes() |> takewhile$(x -> x < 60) |> list

5. Ввести сопоставление с шаблоном

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

from itertools import count, takewhiledef primes():    def sieve([head] :: tail):        return [head] :: sieve(n for n in tail if n % head)    return sieve(count(2))primes() |> takewhile$(x -> x < 60) |> list

6. Преобразовать функции в выражения

Во многих функциональных языках вся работа происходит с выражениями. При таком подходе последнее вычисленное выражение автоматически возвращает значение, и поэтому отпадает необходимость в указании возвращаемого значения. В сущности все сводится к удалению ключевого слова return и введению символа = вместо символа : для определения функции как выражения.

from itertools import count, takewhiledef primes() =    def sieve([x] :: xs) = [x] :: sieve(n for n in xs if n % x)    sieve(count(2))primes() |> takewhile$(x -> x < 60) |> list

7. Использовать встроенные высокопорядковые функции

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

def primes() =    def sieve([x] :: xs) = [x] :: sieve(n for n in xs if n % x)    sieve(count(2))primes() |> takewhile$(x -> x < 60) |> list
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59]

В итоге мы получили полностью функциональный код. Весь мыслительный процесс основан на определениях: функция primes определяется как выражение sieve и его вызов, а определение sieve состоит из итераторной цепочки. Начав с императивного кода:

from itertools import count, takewhiledef primes():    def sieve(numbers):        head = next(numbers)        yield head        yield from sieve(n for n in numbers if n % head)    return sieve(count(2))list(takewhile(lambda x: x < 60, primes()))

мы пришли к чистому функциональному коду:

def primes() =    def sieve([x] :: xs) = [x] :: sieve(n for n in xs if n % x)    sieve(count(2))primes() |> takewhile$(x -> x < 60) |> list

Обратите внимание, насколько версия кода на языке Coconut похожа на версию кода на языке Haskell:

primes :: [Int]primes = sieve [2..]where    sieve (x :: xs) = x : sieve (filter (\n -> n `rem` x /= 0) xs    sieve []        = []                                 ?> takewhile (<60) primes 

Еще несколько примеров

  • Сопоставление с шаблонами

def quick_sort([]) = []@addpattern(quick_sort)def quick_sort([head] + tail) =    """Отсортировать последовательность,     используя быструю сортировку."""    (quick_sort([x for x in tail if x < head])    + [head]    + quick_sort([x for x in tail if x >= head]))    quick_sort([3,6,9,2,7,0,1,4,7,8,3,5,6,7])
[0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 7, 8, 9]
  • Алгебраические типы данных

data vector2(x, y):    """Immutable two-element vector."""    def __abs__(self):        return (self.x**2 + self.y**2)**.5data Empty()data Leaf(n)data Node(l, r)def size(Empty()) = 0@addpattern(size)def size(Leaf(n)) = 1@addpattern(size)def size(Node(l, r)) = size(l) + size(r)
  • Оптимизация хвостовых вызовов

def factorial(0, acc=1) = acc@addpattern(factorial)def factorial(n is int, acc=1 if n > 0) =    """Вычислить n!, где n - это целое число >= 0."""    factorial(n-1, acc*n)def is_even(0) = True@addpattern(is_even)def is_even(n is int if n > 0) = is_odd(n-1)def is_odd(0) = False@addpattern(is_odd)def is_odd(n is int if n > 0) = is_even(n-1)factorial(6)  # 720
  • Рекурсивный итератор

@recursive_iteratordef fib_seq() =    """Бесконечная последовательность чисел Фибоначчи."""    (1, 1) :: map((+), fib_seq(), fib_seq()$[1:])            fib_seq()$[:10] |> parallel_map$(pow$(?, 2)) |> list
[1, 1, 4, 9, 25, 64, 169, 441, 1156, 3025]
  • Конвейер

"Здравствуй, Мир!" |> x -> x.replace('Мир', 'Coconut') |> print
Здравствуй, Coconut!
  • Прочее

product = reduce$(*)def zipwith(f, *args) =    zip(*args) |> map$(items -> f(*items))    list(zipwith(lambda x: x > 4, [1,2,3,4,5,6,7,8,9,0]))
[False, False, False, False, True, True, True, True, True, False]

Выводы

Надеюсь, что наглядность приведенных выше примеров вызовет интерес у читателей и побудит их заняться более глубоким изучением парадигмы ФП. Фактически Coconut предлагает синтаксический сахар, т.е. ряд оптимизаций в написании кода, которые превращают код в функциональный, являясь игровой площадкой для тестирования идей с использованием парадигмы функционального программирования.

Справочные материалы:

Пост подготовлен с использованием информации веб-сайта языка и материалов Энтони Квонга.

Подробнее..

Python и статистический вывод часть 2

11.05.2021 18:04:27 | Автор: admin

Предыдущий пост см. здесь.

Выборки и популяции

В статистической науке термины выборка и популяция имеют особое значение. Популяция, или генеральная совокупность, это все множество объектов, которые исследователь хочет понять или в отношении которых сделать выводы. Например, во второй половине 19-го века основоположник генетики Грегор Йохан Мендель) записывал наблюдения о растениях гороха. Несмотря на то, что он изучал в лабораторных условиях вполне конкретные сорта растения, его задача состояла в том, чтобы понять базовые механизмы, лежащие в основе наследственности абсолютно всех возможных сортов гороха.

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

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

Статистики это атрибуты, которые мы можем измерить на основе выборок. Параметры это атрибуты популяции, которые мы пытаемся вывести статистически.

В действительности, статистики и параметры различаются в силу применения разных символов в математических формулах:

Мера

Выборочная статистика

Популяционный параметр

Объем

n

N

Среднее значение

x

x

Стандартное отклонение

Sx

x

Стандартная ошибка

Sx

Если вы вернетесь к уравнению стандартной ошибки, то заметите, что она вычисляется не из выборочного стандартного отклонения Sx, а из популяционного стандартного отклонения x. Это создает парадоксальную ситуацию мы не можем вычислить выборочную статистику, используя для этого популяционные параметры, которые мы пытаемся вывести. На практике, однако, предполагается, что выборочное и популяционное стандартные отклонения одинаковы при размере выборки порядка n 30.

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

def ex_2_8():  '''Вычислить стандартную ошибку  средних значений за определенный день''' may_1 = '2015-05-01' df = with_parsed_date( load_data('dwell-times.tsv') )  filtered = df.set_index( ['date'] )[may_1] se = standard_error( filtered['dwell-time'] ) print('Стандартная ошибка:', se)
Стандартная ошибка: 3.627340273094217

Хотя мы взяли выборку всего из одного дня, вычисляемая нами стандартная ошибка очень близка к стандартному отклонению всех выборочных средних 3.6 сек. против 3.7 сек. Это, как если бы, подобно клетке, содержащей ДНК, в каждой выборке была закодирована информация обо всей находящейся внутри нее популяции.

Интервалы уверенности

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

Понятия степень уверенности и ожидаемый диапазон, взятые вместе, дают определение термину интервал уверенности.

Примечание. В большинстве языков под термином confidence в контексте инференциальной статистики понимается именно уверенность в отличие от отечественной статистики, где принято говорить о доверительном интервале. На самом деле речь идет не о доверии (trust), а об уверенности исследователя в полученных результатах. Это яркий пример мягкой подмены понятия. Подобного рода ошибки вполне объяснимы - первые переводы появились еще в доколумбову доинтернетовскую эпоху, когда источников было мало, и приходилось домысливать в силу своего понимания. Сегодня же, когда существует масса профильных глоссариев, словарей и источников, такого рода искажения не оправданы. ИМХО.

При установлении интервалов уверенности обычной практикой является задание интервала размером 95% мы на 95% уверены, что популяционный параметр находится внутри интервала. Разумеется, еще остается 5%-я возможность, что он там не находится.

Какой бы ни была стандартная ошибка, 95% популяционного среднего значения будет находиться между -1.96 и 1.96 стандартных отклонений от выборочного среднего. И, следовательно, число 1.96 является критическим значением для 95%-ого интервала уверенности. Это критическое значение носит название z-значения.

Название z-значение вызвано тем, что нормальное распределение называется z-распределением. Впрочем, иногда z-значение так и называют гауссовым значением.

Число 1.96 используется так широко, что его стоит запомнить. Впрочем, критическое значение мы можем вычислить сами, воспользовавшись функцией scipy stats.norm.ppf. Приведенная ниже функция confidence_interval ожидает значение для p между 0 и 1. Для нашего 95%-ого интервала уверенности оно будет равно 0.95. В целях вычисления положения каждого из двух хвостов нам нужно вычесть это число из единицы и разделить на 2 (2.5% для интервала уверенности шириной 95%):

def confidence_interval(p, xs): '''Интервал уверенности''' mu = xs.mean() se = standard_error(xs) z_crit = stats.norm.ppf(1 - (1-p) / 2)  return [mu - z_crit * se, mu + z_crit * se]def ex_2_9(): '''Вычислить интервал уверенности для данных за определенный день''' may_1 = '2015-05-01' df = with_parsed_date( load_data('dwell-times.tsv') )  filtered = df.set_index( ['date'] )[may_1] ci = confidence_interval(0.95, filtered['dwell-time']) print('Интервал уверенности: ', ci)
Интервал уверенности: [83.53415272762004, 97.753065317492741]

Полученный результат говорит о том, что можно на 95% быть уверенным в том, что популяционное среднее находится между 83.53 и 97.75 сек. И действительно, популяционное среднее, которое мы вычислили ранее, вполне укладывается в этот диапазон.

Сравнение выборок

После вирусной маркетинговой кампании веб-команда в AcmeContent извлекает для нас однодневную выборку времени пребывания посетителей на веб-сайте для проведения анализа. Они хотели бы узнать, не привлекла ли их недавняя кампания более активных посетителей веб-сайта. Интервалы уверенности предоставляют нам интуитивно понятный подход к сравнению двух выборок.

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

def ex_2_10():    '''Сводные статистики данных, полученных        в результате вирусной кампании'''    ts = load_data('campaign-sample.tsv')['dwell-time']         print('n:                      ', ts.count())    print('Среднее:                ', ts.mean())    print('Медиана:                ', ts.median())    print('Стандартное отклонение: ', ts.std())    print('Стандартная ошибка:     ', standard_error(ts))    ex_2_10()
n:                       300Среднее:                 130.22Медиана:                 84.0Стандартное отклонение:  136.13370714388034Стандартная ошибка:      7.846572839994115

Среднее значение выглядит намного больше, чем то, которое мы видели ранее 130 сек. по сравнению с 90 сек. Вполне возможно, здесь имеется некое значимое расхождение, хотя стандартная ошибка более чем в 2 раза больше той, которая была в предыдущей однодневной выборке, в силу меньшего размера выборки и большего стандартного отклонения. Основываясь на этих данных, можно вычислить 95%-й интервал уверенности для популяционного среднего, воспользовавшись для этого той же самой функцией confidence_interval, что и прежде:

def ex_2_11(): '''Интервал уверенности для данных, полученных в результате вирусной кампании''' ts = load_data('campaign-sample.tsv')['dwell-time']  print('Интервал уверенности:', confidence_interval(0.95, ts))
Интервал уверенности: [114.84099983154137, 145.59900016845864]

95%-ый интервал уверенности для популяционного среднего лежит между 114.8 и 145.6 сек. Он вообще не пересекается с вычисленным нами ранее популяционным средним в размере 90 сек. Похоже, имеется какое-то крупное расхождение с опорной популяцией, которое едва бы произошло по причине одной лишь ошибки выборочного обследования. Наша задача теперь состоит в том, чтобы выяснить почему это происходит.

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

Искаженность

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

Широко известным примером искажения при взятии выборки является опрос населения, проведенный в США еженедельным журналом Литературный Дайджест (Literary Digest) по поводу президентских выборов 1936 г. Это был один из самых больших и самых дорогостоящих когда-либо проводившихся опросов: тогда по почте было опрошено 2.4 млн. человек. Результаты были однозначными губернатор-республиканец от шт. Канзас Альфред Лэндон должен был победить Франклина Д. Рузвельта с 57% голосов. Как известно, в конечном счете на выборах победил Рузвельт с 62% голосов.

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

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

Если мы откроем файл campaign_sample.tsv, то обнаружим, что наша выборка приходится исключительно на 6 июня 2015 года. Это был выходной день, и этот факт мы можем легко подтвердить при помощи функции pandas:

'''Проверка даты''' d = pd.to_datetime('2015 6 6') d.weekday() in [5,6]
True

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

Визуализация разных популяций

Теперь снимем фильтр для рабочих дней и построим график среднесуточного времени пребывания для всех дней недели рабочих и выходных:

def ex_2_12():  '''Построить график времени ожидания  по всем дням, без фильтра''' df = load_data('dwell-times.tsv') means = mean_dwell_times_by_date(df)['dwell-time'] means.hist(bins=20) plt.xlabel('Ежедневное время ожидания неотфильтрованное, сек.') plt.ylabel('Частота') plt.show()

Этот пример сгенерирует следующую ниже гистограмму:

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

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

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

def ex_2_13():    '''Сводные статистики данных,       отфильтрованных только по выходным дням'''    df = with_parsed_date( load_data('dwell-times.tsv') )    df.index = df['date']    df = df[df['date'].index.dayofweek > 4]   # суббота-воскресенье    weekend_times = df['dwell-time']      print('n:                      ', weekend_times.count())    print('Среднее:                ', weekend_times.mean())    print('Медиана:                ', weekend_times.median())    print('Стандартное отклонение: ', weekend_times.std())    print('Стандартная ошибка:     ', standard_error(weekend_times))        
n:                       5860Среднее:                 117.78686006825939Медиана:                 81.0Стандартное отклонение:  120.65234077179436Стандартная ошибка:      1.5759770362547678

Итоговое среднее значение в выходные дни (на основе 6-ти месячных данных) составляет 117.8 сек. и попадает в пределы 95%-ого интервала уверенности для маркетинговой выборки. Другими словами, хотя среднее значение времени пребывания в размере 130 сек. является высоким даже для выходных, расхождение не настолько большое, что его нельзя было бы приписать простой случайной изменчивости в выборке.

Мы только что применили подход к установлению подлинного расхождения в популяциях (между посетителями веб-сайта в выходные по сравнению с посетителями в будние дни), который при проведении проверки обычно не используется. Более традиционный подход начинается с выдвижения гипотетического предположения, после чего это предположение сверяется с данными. Для этих целей статистический метод анализа определяет строгий подход, который называется проверкой статистических гипотез.

Это и будет темой следующего поста, поста 3.

Примеры исходного кода для этого поста находятся в моемрепона Github. Все исходные данные взяты врепозиторииавтора книги.

Подробнее..

Python и статистический вывод часть 4

12.05.2021 06:16:40 | Автор: admin

Этот заключительный пост посвящен анализу дисперсии. Предыдущий пост см. здесь.

Анализ дисперсии

Анализ дисперсии (варианса), который в специальной литературе также обозначается как ANOVA от англ. ANalysis Of VAriance, это ряд статистических методов, используемых для измерения статистической значимости расхождений между группами. Он был разработан чрезвычайно одаренным статистиком Рональдом Фишером, который также популяризировал процедуру проверки статистической значимости в своих исследовательских работах по биологическому тестированию.

Примечание. В предыдущей и этой серии постов для термина variance использовался принятый у нас термин дисперсия и в скобках местами указывался термин варианс. Это не случайно. За рубежом существуют парные термины variance и covariance, и они по идее должны переводиться с одним корнем, например, как варианс и коварианс, однако на деле у нас парная связь разорвана, и они переводятся как совершенно разные дисперсия и ковариация. Но это еще не все. Dispersion (статистическая дисперсия) за рубежом является отдельным родовым понятием разбросанности, т.е. степени, с которой распределение растягивается или сжимается, а мерами статистической дисперсии являются варианс, стандартное отклонение и межквартильный размах. Dispersion, как родовое понятие разбросанности, и variance, как одна из ее мер, измеряющая расстояние от среднего значения - это два разных понятия. Далее в тексте для variance везде будет использоваться общепринятый термин дисперсия. Однако данное расхождение в терминологии следует учитывать.

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

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

Длительности (сек), постранично и совмещенноДлительности (сек), постранично и совмещенно

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

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

F-распределение

F-распределение параметризуется двумя степенями свободы степенями свободы размера выборки и числа групп.

Первая степень свободы это количество групп минус 1, и вторая степень свободы размер выборки минус число групп. Если k представляет число групп, и n объем выборки, то получаем:

df_1=k-1df_2=n-k

Мы можем визуализировать разные F-распределения на графике при помощи функции библиотеки pandas plot:

def ex_2_Fisher(): '''Визуализация разных F-распределений на графике''' mu = 0 d1_values, d2_values = [4, 9, 49], [95, 90, 50] linestyles = ['-', '--', ':', '-.'] x = sp.linspace(0, 5, 101)[1:]  ax = None for (d1, d2, ls) in zip(d1_values, d2_values, linestyles): dist = stats.f(d1, d2, mu) df = pd.DataFrame( {0:x, 1:dist.pdf(x)} )  ax = df.plot(0, 1, ls=ls,  label=r'$d_1=%i,\ d_2=%i$' % (d1,d2), ax=ax) plt.xlabel('$x$\nF-статистика') plt.ylabel('Плотность вероятности \n$p(x|d_1, d_2)$') plt.show()

Кривые приведенного выше графика показывают разные F-распределения для выборки, состоящей из 100 точек, разбитых на 5, 10 и 50 групп.

F-статистика

Тестовая выборочная величина, которая представляет соотношение дисперсии внутри и между группами, называется F-статистикой. Чем ближе значение F-статистики к единице, тем более похожи обе дисперсии. F-статистика вычисляется очень просто следующим образом:

где S2b это межгрупповая дисперсия, и S2w внутригрупповая дисперсия.

По мере увеличения соотношения F межгрупповая дисперсия увеличивается по сравнению с внутригрупповой. Это означает, что это разбиение на группы хорошо справляется с задачей объяснения дисперсии, наблюдавшейся по всей выборке в целом. Там, где это соотношение превышает критический порог, мы можем сказать, что расхождение является статистически значимым.

F-тест всегда является односторонним, потому что любая дисперсия среди групп демонстрирует тенденцию увеличивать F. При этом F не может уменьшаться ниже нуля.

Внутригрупповая дисперсия для F-теста вычисляется как среднеквадратичное отклонение от среднего значения. Мы вычисляем ее как сумму квадратов отклонений от среднего значения, деленную на первую степень свободы. Например, если имеется kгрупп, каждая со средним значением xk, то мы можем вычислить внутригрупповую дисперсию следующим образом:

где SSW это внутригрупповая сумма квадратов, и xjk это значение j-ого элемента в группе .

Приведенная выше формула для вычисления SSW имеет грозный вид, но на деле довольно легко имплементируется на Python, как сумма квадратичных отклонений от среднего значения ssdev, делающая вычисление внутригрупповой суммы квадратов тривиальным:

def ssdev( xs ): '''Сумма квадратов отклонений между  каждым элементом и средним по выборке''' mu = xs.mean()  square_deviation = lambda x : (x - mu) ** 2  return sum( map(square_deviation, xs) )

Межгрупповая дисперсия для F-теста имеет похожую формулу:

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

Отсюда, SST это попросту полная сумма квадратов без какого-либо разбиения на группы. На языке Python значения SST и SSW вычисляются элементарно, как будет показано ниже.

ssw = sum( groups.apply( lambda g: ssdev(g) ) ) # внутригрупповая сумма # квадратов отклонений sst = ssdev( df['dwell-time'] ) # полная сумма квадратов по всему наборуssb = sst  ssw # межгрупповая сумма квадратов отклонений

F-статистика вычисляется как отношение межгрупповой дисперсии к внутригрупповой. Объединив определенные ранее функции ssb и ssw и две степени свободы, мы можем вычислить F-статистика.

На языке Python F-статистика из групп и двух степеней свободы вычисляется следующим образом:

msb = ssb / df1 # усредненная межгрупповаяmsw = ssw / df2 # усредненная внутригрупповаяf_stat = msb / msw

Имея возможность вычислить F-статистику из групп, мы теперь готовы использовать его в соответствующем F-тесте.

F-тест

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

Библиотека scipy предлагает функцию stats.f.sf, но она измеряет дисперсию между и внутри всего двух групп. В целях выполнения F-теста на наших 20 разных группах, нам придется имплементировать для нее нашу собственную функцию. К счастью, мы уже проделали всю тяжелую работу в предыдущих разделах, вычислив надлежащую F-статистику. Мы можем выполнить F-тест, отыскав F-статистику в F-распределении, параметризованном правильными степенями свободы. В следующем ниже примере мы напишем функцию f_test, которая все это использует для выполнения теста на произвольном числе групп:

def f_test(groups): m, n = len(groups), sum(groups.count()) df1, df2 = m - 1, n - m  ssw = sum( groups.apply(lambda g: ssdev(g)) )  sst = ssdev( df['dwell-time'] )  ssb = sst - ssw  msb = ssb / df1  msw = ssw / df2  f_stat = msb / msw return stats.f.sf(f_stat, df1, df2)    def ex_2_24(): '''Проверка вариантов дизайна веб-сайта на основе F-теста''' df = load_data('multiple-sites.tsv') groups = df.groupby('site')['dwell-time'] return f_test(groups)
0.014031745203658217

В последней строке приведенной выше функции мы преобразуем значение F-статистики в p-значение, пользуясь функцией scipy stats.f.sf, параметризованной правильными степенями свободы. P-значение является мерой всей модели, т.е. насколько хорошо разные веб-сайты объясняют дисперсию времени пребывания в целом. Нам остается только выбрать уровень значимости и выполнить проверку. Будем придерживаться 5%-ого уровня значимости.

Проверка возвращает p-значение, равное 0.014, т.е. значимый результат. Разные варианты веб-сайта действительно имеют разные дисперсии, которые нельзя просто объяснить одной лишь случайной ошибкой в выборке.

F-распределение со степенями свободы 19 и 980F-распределение со степенями свободы 19 и 980

Для визуализации распределений всех вариантов дизайна веб-сайта на одном графике мы можем воспользоваться коробчатой диаграммой, разместив распределения для сопоставления рядом друг с другом:

def ex_2_25(): '''Визуализация распределений всех вариантов  дизайна веб-сайта на одной коробчатой диаграмме''' df = load_data('multiple-sites.tsv') df.boxplot(by='site', showmeans=True) plt.xlabel('Номер дизайна веб-сайта') plt.ylabel('Время пребывания, сек.') plt.title('') plt.suptitle('') plt.show()

В приведенном выше примере показана работа функции boxplot, которая вычисляет свертку на группах и сортирует группы по номеру варианта дизайна веб-сайта. Соответственно наш изначальный веб-сайт с номером 0, на графике расположен крайним слева.

Может создастся впечатление, что вариант дизайна веб-сайта с номером 10 имеет самое длительное время пребывания, поскольку его межквартильный размах простирается вверх выше других. Однако, если вы присмотритесь повнимательнее, то увидите, что его среднее значение меньше, чем у варианта дизайна с номером 6, имеющего среднее время пребывания более 144 сек.:

def ex_2_26(): '''T-проверка вариантов 0 и 10 дизайна веб-сайта''' df = load_data('multiple-sites.tsv') groups = df.groupby('site')['dwell-time'] site_0 = groups.get_group(0)  site_10 = groups.get_group(10) _, p_val = stats.ttest_ind(site_0, site_10, equal_var=False) return p_val
0.0068811940138903786

Подтвердив статистически значимый эффект при помощи F-теста, теперь мы вправе утверждать, что вариант дизайна веб-сайта с номером 6 статистически отличается от изначального значения:

def ex_2_27(): '''t-тест вариантов 0 и 6 дизайна веб-сайта''' df = load_data('multiple-sites.tsv') groups = df.groupby('site')['dwell-time'] site_0 = groups.get_group(0)  site_6 = groups.get_group(6) _, p_val = stats.ttest_ind(site_0, site_6, equal_var=False) return p_val
0.005534181712508717

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

Размер эффекта

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

Интервальный индекс d Коэна

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

Здесь Sab это объединенное стандартное отклонение (не объединенная стандартная ошибка) выборок. Она вычисляется аналогично вычислению объединенной стандартной ошибки:

def pooled_standard_deviation(a, b): '''Объединенное стандартное отклонение  (не объединенная стандартная ошибка)''' return sp.sqrt( standard_deviation(a) ** 2 + standard_deviation(b) ** 2)

Так, для варианта под номером 6 дизайна нашего веб-сайта мы можем вычислить индекс dКоэна следующим образом:

def ex_2_28(): '''Вычисление интервального индекса d Коэна  для варианта дизайна веб-сайта под номером 6''' df = load_data('multiple-sites.tsv') groups = df.groupby('site')['dwell-time'] a = groups.get_group(0) b = groups.get_group(6) return (b.mean() - a.mean()) / pooled_standard_deviation(a, b)
0.38913648705499848

В отличие от p-значений, абсолютный порог для индекса d Коэна отсутствует. Считать ли эффект большим или нет частично зависит от контекста, однако этот индекс действительно предоставляет полезную, нормализованную меру величины эффекта. Значения выше 0.5, как правило, считаются большими, поэтому значение 0.38 это умеренный эффект. Он определенно говорит о значительном увеличении времени пребывания на нашем веб-сайте и что усилия, потраченные на обновление веб-сайта, определенно не были бесполезными.

Примеры исходного кода для этого поста находятся в моемрепона Github. Все исходные данные взяты врепозиторииавтора книги.

Резюме

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

Мы узнали о том, каким именно образом методология инференциальной статистики анализирует непосредственно сами выборки, чтобы выдвигать утверждения о всей популяции в целом, из которой они были отобраны. Мы познакомились с целым рядом методов интервалами уверенности, размножением выборок путем бутстрапирования и проверкой статистической значимости которые помогают разглядеть глубинные параметры популяции. Симулируя многократные испытания, мы также получили представление о трудности проверки статистической значимости в условиях многократных сравнений и увидели, как F-тест помогает решать эту задачу и устанавливать равновесие между ошибками 1-го и 2-го рода.

Мы также коснулись терминологических болевых точек и выяснили некоторые нюансы смыслового дрейфа в отечественной статистике.

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

Подробнее..

Python и статистический вывод часть 3

12.05.2021 06:16:40 | Автор: admin

Предыдущий пост см. здесь.

Проверка статистических гипотез

Для статистиков и исследователей данных проверка статистической гипотезы представляет собой формальную процедуру. Стандартный подход к проверке статистической гипотезы подразумевает определение области исследования, принятие решения в отношении того, какие переменные необходимы для измерения предмета изучения, и затем выдвижение двух конкурирующих гипотез. Во избежание рассмотрения только тех данных, которые подтверждают наши субъективные оценки, исследователи четко констатируют свою гипотезу заранее. Затем, основываясь на данных, они применяют выборочные статистики с целью подтвердить либо отклонить эту гипотезу.

Проверка статистической гипотезы подразумевает использование тестовой статистики, т.е. выборочной величины, как функции от результатов наблюдений. Тестовая статистика (test statistic) - это вычисленная из выборочных данных величина, которая используется для оценивания прочности данных, подтверждающих нулевую статистическую гипотезу и служит для выявления меры расхождения между эмпирическими и гипотетическими значениями. Конкретные методы проверки называются тестами, например, z-тест, t-тест (соответственно z-тест Фишера, t-тест Студента) и т.д. в зависимости от применяемых в них тестовых статистик.

Примечание. В отечественной статистической науке используется туманный термин статистика критерия. Туманный потому здесь мы снова наблюдаем мягкую подмену: вместо теста возникает критерий. Если уж на то пошло, то критерий - это принцип или правило. Например, выполняя z-тест, t-тест и т.д., мы соответственно используем z-статистику, t-статистику и т.д. в правиле отклонения гипотезы. Это хорошо резюмируется следующей ниже таблицей:

Тестирование гипотезы

Тестовая статистика

Правило, или критерий, отклонения гипотезы

z-тесты

z-статистика

Если тестовая статистика z или -z, то отклонить нулевую гипотезу H0.

t-тесты

t-статистика

Если тестовая статистика t или -t, то отклонить нулевую гипотезу H0.

Анализ дисперсии (ANOVA)

F-статистика

Если тестовая статистика F, то отклонить нулевую гипотезу H0.

Тесты хи-квадрат

Статистика хи-квадрат

Если тестовая статистика , то отклонить нулевую гипотезу H0.

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

Отсюда главный вопрос нашего исследования состоит в том, приводит ли обновленный вид веб-сайта к увеличению времени пребывания на нем посетителей? Мы принимаем решение проверить его относительно среднего значения времени пребывания. Теперь, мы должны изложить две наши гипотезы. По традиции считается, что изучаемые данные не содержат того, что исследователь ищет. Таким образом, консервативное мнение заключается в том, что данные не покажут ничего необычного. Все это называется нулевой гипотезой и обычно обозначается как H0.

При тестировании статистической гипотезы исходят из того, что нулевая гипотеза является истинной до тех пор, пока вес представленных данных, подтверждающих обратное, не сделает ее неправдоподобной. Этот подход к поиску доказательств в обратную сторону частично вытекает из простого психологического факта, что, когда люди пускаются на поиски чего-либо, они, как правило, это находят.

Затем исследователь формулирует альтернативную гипотезу, обозначаемую как H1. Она может попросту заключаться в том, что популяционное среднее отличается от базового уровня. Или же, что популяционное среднее больше или меньше базового уровня, либо больше или меньше на некоторую указанную величину. Мы хотели бы проверить, не увеличивает ли обновленный дизайн веб-сайта время пребывания, и поэтому нашей нулевой и альтернативной гипотезами будут следующие:

  • H0: Время пребывания для обновленного веб-сайта не отличается от времени пребывания для существующего веб-сайта

  • H1: Время пребывания для обновленного веб-сайта больше по сравнению с временем пребывания для существующего веб-сайта

Наше консервативное допущение состоит в том, что обновленный веб-сайт никак не влияет на время пребывания посетителей на веб-сайте. Нулевая гипотеза не обязательно должна быть нулевой (т.е. эффект отсутствует), но в данном случае, у нас нет никакого разумного оправдания, чтобы считать иначе. Если выборочные данные не поддержат нулевую гипотезу (т.е. если данные расходятся с ее допущением на слишком большую величину, чтобы носить случайный характер), то мы отклоним нулевую гипотезу и предложим альтернативную в качестве наилучшего альтернативного объяснения.

Указав нулевую и альтернативную гипотезы, мы должны установить уровень значимости, на котором мы ищем эффект.

Статистическая значимость

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

Следовательно, существует два риска:

  • Мы можем принять расхождение как значимое, когда на самом деле оно возникло случайным образом

  • Мы можем приписать расхождение случайности, когда на самом деле оно показывает истинное расхождение с популяцией

Эти две возможности обозначаются соответственно, как ошибки 1-го и 2-го рода:

H0ложная

H0истинная

Отклонить H0

Истинноотрицательный исход

Ошибка 1-го рода (ложноположительный исход)

Принять H0

Ошибка 2-го рода (ложноотрицательный исход)

Истинноположительный исход

Чем больше мы уменьшаем риск совершения ошибок 1-го рода, тем больше мы увеличиваем риск совершения ошибок 2-го рода. Другими словами, с чем большей уверенностью мы хотим не заявлять о наличии расхождения, когда его нет, тем большее расхождение между выборками нам потребуется, чтобы заявить о статистической значимости. Эта ситуация увеличивает вероятность того, что мы проигнорируем подлинное расхождение, когда мы с ним столкнемся.

В статистической науке обычно используются два порога значимости. Это уровни в 5% и 1%. Расхождение в 5% обычно называют значимым, а расхождение в 1% крайне значимым. В формулах этот порог часто обозначается греческой буквой (альфа) и называется уровнем значимости. Поскольку, отсутствие эффекта по результатам эксперимента может рассматриваться как неуспех (эксперимента либо обновленного веб-сайта, как в нашем случае), то может возникнуть желание корректировать уровень значимости до тех пор, пока эффект не будет найден. По этой причине классический подход к проверке статистической значимости требует, чтобы мы устанавливали уровень значимости до того, как обратимся к нашим данным. Часто выбирается уровень в 5%, и поэтому мы на нем и остановимся.

Проверка обновленного дизайна веб-сайта

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

Вместо того, чтобы запустить его для всех пользователей сразу, в AcmeContent хотели бы сначала проверить веб-сайт на небольшой выборке посетителей. Мы познакомили веб-команду с понятием искаженности выборки, и в результате там решили в течение одного дня перенаправлять случайные 5% трафика на обновленный веб-сайт. Результат с дневным трафиком был нам предоставлен одним текстовым файлом. Каждая строка показывает время пребывания посетителей. При этом, если посетитель пользовался исходным дизайном, ему присваивалось значение "0", и если он пользовался обновленным (и надеемся, улучшенным) дизайном, то ему присваивалось значение "1".

Выполнение z-теста

Ранее при тестировании с интервалами уверенности мы располагали лишь одним популяционным средним, с которым и выполнялось сравнение.

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

Поскольку в нашем распоряжении имеется две выборки, то и стандартных ошибок у нас тоже две. Z-тест выполняется относительно объединенной стандартной ошибки, т.е. квадратного корня суммы дисперсий (вариансов), деленных на размеры выборок. Она будет такой же, что и результат, который мы получим, если взять стандартную ошибку обеих выборок вместе:

Здесь 2a это дисперсия выборки a, 2b дисперсия выборки bи соответственно na и nb размеры выборок a и b. На Python объединенная стандартная ошибка вычисляется следующим образом:

def pooled_standard_error(a, b, unbias=False): '''Объединенная стандартная ошибка''' std1 = a.std(ddof=0) if unbias==False else a.std()  std2 = b.std(ddof=0) if unbias==False else b.std() x = std1 ** 2 / a.count() y = std2 ** 2 / b.count() return sp.sqrt(x + y)

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

Используя функции pooled_standard_error, которая вычисляет объединенную стандартную ошибку, z-статистику можно получить следующим образом:

def z_stat(a, b, unbias=False): return (a.mean() - b.mean()) / pooled_standard_error(a, b, unbias)

Соотношение z объясняет, насколько средние значения отличаются относительно величины, которую мы ожидаем при заданной стандартной ошибке. Следовательно, z-статистика сообщает нам о том, на какое количество стандартных ошибок расходятся средние значения. Поскольку стандартная ошибка имеет нормальное распределение вероятностей, мы можем связать это расхождение с вероятностью, отыскав z-статистику в нормальной ИФР:

def z_test(a, b):  return stats.norm.cdf([ z_stat(a, b) ])

В следующем ниже примере z-тест используется для сравнения результативность двух веб-сайтов. Это делается путем группировки строк по номеру веб-сайта, в результате чего возвращается коллекция, в которой конкретному веб-сайту соответствует набор строк. Мы вызываем groupby('site')['dwell-time'] для конвертирования набора строк в набор значений времени пребывания. Затем вызываем функцию get_group с номером группы, соответствующей номеру веб-сайта:

def ex_2_14():    '''Сравнение результативности двух вариантов       дизайна веб-сайта на основе z-теста'''    groups = load_data('new-site.tsv').groupby('site')['dwell-time']    a = groups.get_group(0)    b = groups.get_group(1)         print('a n:         ', a.count())    print('b n:         ', b.count())    print('z-статистика:', z_stat(a, b))    print('p-значение:  ', z_test(a, b))
a n:          284b n:          16z-статистика: -1.6467438180091214p-значение:   [0.04980536]

Установление уровня значимости в размере 5% во многом аналогично установлению интервала уверенности шириной 95%. В сущности, мы надеемся убедиться, что наблюдавшееся расхождение попадает за пределы 95%-го интервала уверенности. Если это так, то мы можем утверждать, что нашли результат с 5%-ым уровнем значимости.

P-значение это вероятность совершения ошибки 1-го рода в результате неправильного отклонения нулевой гипотезы, которая в действительности является истинной. Чем меньше p-значение, тем больше определенность в том, что нулевая гипотеза является ложной, и что мы нашли подлинный эффект.

Этот пример возвращает значение 0.0498, или 4.98%. Поскольку оно немногим меньше нашего 5% порога значимости, мы можем утверждать, что нашли нечто значимое.

Приведем еще раз нулевую и альтернативную гипотезы:

  • H0: Время пребывания на обновленном веб-сайте не отличается от времени пребывания на существующем веб-сайте

  • H1: Время пребывания на обновленном веб-сайте превышает время пребывания на существующем веб-сайте.

Наша альтернативная гипотеза состоит в том, что время пребывания на обновленном веб-сайте больше.

Мы готовы заявить о статистической значимости, и что время пребывания на обновленном веб-сайте больше по сравнению с существующим веб-сайтом, но тут есть одна трудность чем меньше размер выборки, тем больше неопределенность в том, что выборочное стандартное отклонение совпадет с популяционным. Как показано в результатах предыдущего примера, наша выборка из обновленного веб-сайта содержит всего 16 посетителей. Столь малые выборки делают невалидным допущение о том, что стандартная ошибка нормально распределена.

К счастью, существует тест и связанное с ним распределение, которое моделирует увеличенную неопределенность стандартных ошибок для выборок меньших размеров.

t-распределение Студента

Популяризатором t-распределения был химик, работавший на пивоварню Гиннес в Ирландии, Уилльям Госсетт, который включил его в свой анализ темного пива Стаут.

В 1908 Уильям Госсет опубликовал статью об этой проверке в журнале Биометрика, но при этом по распоряжению своего работодателя, который рассматривал использованную Госсеттом статистику как коммерческую тайну, был вынужден использовать псевдоним. Госсет выбрал псевдоним Студент.

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

Нормальное распределение, t-распределение со степенью свободы df = 20 и степенью свободы df = 5Нормальное распределение, t-распределение со степенью свободы df = 20 и степенью свободы df = 5

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

Степени свободы

Степени свободы, часто обозначаемые сокращенно df от англ. degrees of freedom, тесно связаны с размером выборки. Это полезная статистика и интуитивно понятное свойство числового ряда, которое можно легко продемонстрировать на примере.

Если бы вам сказали, что среднее, состоящее из двух значений, равно 10 и что одно из значений равно 8, то Вам бы не потребовалась никакая дополнительная информация для того, чтобы суметь заключить, что другое значение равно 12. Другими словами, для размера выборки, равного двум, и заданного среднего значения одно из значений ограничивается, если другое известно.

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

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

При сопоставлении двух выборок степени свободы на две единицы меньше суммы размеров этих выборок, что равно сумме их индивидуальных степеней свободы.

t-статистика

При использовании t-распределения мы обращаемся к t-статистике. Как и z-статистика, эта величина количественно выражает степень маловероятности отдельно взятого наблюдавшегося отклонения. Для двухвыборочного t-теста соответствующая t-статистика вычисляется следующим образом:

Здесь Sab это объединенная стандартная ошибка. Объединенная стандартная ошибка вычисляется таким же образом, как и раньше:

Однако это уравнение допускает наличие информации о популяционных параметрах aи b, которые можно аппроксимировать только на основе крупных выборок. t-тест предназначен для малых выборок и не требует от нас принимать допущения о поплуляционной дисперсии (вариансе).

Как следствие, объединенная стандартная ошибка для t-теста записывается как квадратный корень суммы стандартных ошибок:

На практике оба приведенных выше уравнения для объединенной стандартной ошибки дают идентичные результаты при заданных одинаковых входных последовательностях. Разница в математической записи всего лишь служит для иллюстрации того, что в условиях t-теста мы на входе зависим только от выборочных статистик. Объединенная стандартная ошибка может быть вычислена следующим образом:

def pooled_standard_error_t(a, b):  '''Объединенная стандартная ошибка для t-теста''' return sp.sqrt(standard_error(a) ** 2 +  standard_error(b) ** 2)

Хотя в математическом плане t-статистика и z-статистика представлены по-разному, на практике процедура вычисления обоих идентичная:

t_stat = z_statdef ex_2_15():    '''Вычисление t-статистики        двух вариантов дизайна веб-сайта'''    groups = load_data('new-site.tsv').groupby('site')['dwell-time']    a = groups.get_group(0)    b = groups.get_group(1)        return t_stat(a, b)
-1.6467438180091214

Различие между двумя выборочными показателями является не алгоритмическим, а концептуальным z-статистика применима только тогда, когда выборки подчинены нормальному распределению.

t-тест

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

def t_test(a, b): df = len(a) + len(b) - 2 return stats.t.sf([ abs(t_stat(a, b)) ], df)

Значение степени свободы обеих выборок на две единицы меньше их размеров, и для наших выборок составляет 298.

t-распределение, степень свободы = 298t-распределение, степень свободы = 298

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

  • H0: Эта выборка взята из популяции с предоставленным средним значением

  • H1: Эта выборка взята из популяции со средним значением большего размера

Выполним следующий ниже пример:

def ex_2_16(): '''Сравнение результативности двух вариантов  дизайна веб-сайта на основе t-теста''' groups = load_data('new-site.tsv').groupby('site')['dwell-time'] a = groups.get_group(0) b = groups.get_group(1)  return t_test(a, b)
array([ 0.05033241])

Этот пример вернет p-значение, составляющее более 0.05. Поскольку оно больше , равного 5%, который мы установили для проверки нулевой гипотезы, то мы не можем ее отклонить. Наша проверка с использованием t-теста значимого расхождения между средними значениями не обнаружила. Следовательно, наш едва значимый результат z-теста отчасти объясняется наличием слишком малой выборки.

Двухсторонние тесты

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

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

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

Хотя более высокая статистическая мощность выглядит желательной, она получается за счет наличия большей вероятности совершить ошибку 1-го рода. Правильнее было бы допустить возможность того, что обновленный веб-сайт может в действительности оказаться хуже существующего. Этот подход распределяет нашу одинаково по обоим хвостам распределения и обеспечивает значимый результат, не искаженный под воздействием априорного допущения об улучшении работы обновленного веб-сайта.

Надписи: t-распределение, степень свободы = 298Надписи: t-распределение, степень свободы = 298

В действительности в модуле stats библиотеки scipy уже предусмотрены функции для выполнения двухвыборочных t-проверок. Это функция stats.ttest_ind. В качестве первого аргумента мы предоставляем выборку данных и в качестве второго - выборку для сопоставления. Если именованный аргумент equal_var равен True, то выполняется стандартная независимая проверка двух выборок, которая предполагает равные популяционные дисперсии, в противном случае выполняется проверка Уэлша (обратите внимание на служебную функцию t_test_verbose, (которую можно найти среди примеров исходного кода в репо):

def ex_2_17(): '''Двухсторонний t-тест''' groups = load_data('new-site.tsv').groupby('site')['dwell-time'] a = groups.get_group(0) b = groups.get_group(1)  return t_test_verbose(a, sample2=b, fn=stats.ttest_ind) #t-тест Уэлша
{'p-значение': 0.12756432502462475, 'степени свободы     ': 17.761382349686098, 'интервал уверенности': (76.00263198799597, 99.89877646270826), 'n1          ': 284, 'n2          ': 16, 'среднее x   ': 87.95070422535211, 'среднее y   ': 122.0, 'дисперсия x ': 10463.941024237296, 'дисперсия y ': 6669.866666666667, 't-статистика': -1.5985205593851322}

По результатам t-теста служебная функция t_test_verbose возвращает много информации и в том числе p-значение. P-значение примерно в 2 раза больше того, которое мы вычислили для односторонней проверки. На деле, единственная причина, почему оно не совсем в два раза больше, состоит в том, что в модуле stats имплементирован легкий вариант t-теста, именуемый t-тестом Уэлша, который немного более робастен, когда две выборки имеют разные стандартные отклонения. Поскольку мы знаем, что для экспоненциальных распределений среднее значение и дисперсия тесно связаны, то этот тест немного более строг в применении и даже возвращает более низкую значимость.

Одновыборочный t-тест

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

Мы передаем выборку и популяционное среднее относительно которого выполняется проверка. Так, если мы просто хотим узнать, не отличается ли обновленный веб-сайт значимо от существующего популяционного среднего времени пребывания, равного 90 сек., то подобную проверку можно выполнить следующим образом:

def ex_2_18(): groups = load_data('new-site.tsv').groupby('site')['dwell-time'] b = groups.get_group(1)  return t_test_verbose(b, mean=90, fn=stats.ttest_1samp) 
{'p-значение          ': 0.13789520958229415, 'степени свободы df  ': 15.0, 'интервал уверенности': (78.4815276659039, 165.5184723340961), 'n1                  ': 16, 'среднее x           ': 122.0, 'дисперсия x         ': 6669.866666666667, 't-статистика        ': 1.5672973291495713}

Служебная функция t_test_verbose не только возвращает p-значение для выполненной проверки, но и интервал уверенности для популяционного среднего. Интервал имеет широкий диапазон между 78.5 и 165.5 сек., и, разумеется, перекрывается 90 сек. нашего теста. Как раз он и объясняет, почему мы не смогли отклонить нулевую гипотезу.

Многократные выборки

В целях развития интуитивного понимания относительно того, каким образом t-тест способен подтвердить и вычислить эти статистики из столь малых данных, мы можем применить подход, который связан с многократными выборками, от англ. resampling. Извлечение многократных выборок основывается на допущении о том, что каждая выборка является лишь одной из бесконечного числа возможных выборок из популяции. Мы можем лучше понять природу того, какими могли бы быть эти другие выборки, и, следовательно, добиться лучшего понимания опорной популяции, путем извлечения большого числа новых выборок из нашей существующей выборки.

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

Бутстраповская выборка, или бутстрап, синтетический набор данных, полученный в результате генерирования повторных выборок (с возвратом) из исследуемой выборки, используемой в качестве суррогатной популяции, в целях аппроксимации выборочного распределения статистики (такой как, среднее, медиана и др.).

В библиотеке pandas при помощи функции sample можно легко извлекать бутстраповские выборки и генерировать большое число многократных выборок. Эта функция принимает ряд опциональных аргументов, в т.ч. n (число элементов, которые нужно вернуть из числового ряда), axis (ось, из которой извлекать выборку) и replace (выборка с возвратом или без), по умолчанию равный False. После этой функции можно задать метод агрегирования, вычисляющий сводную статистику в отношении бутстраповских выборок:

def ex_2_19(): '''Построение графика синтетических времен пребывания  путем извлечения бутстраповских выборок''' groups = load_data('new-site.tsv').groupby('site')['dwell-time'] b = groups.get_group(1)  xs = [b.sample(len(b), replace=True).mean() for _ in range(1000)]  pd.Series(xs).hist(bins=20) plt.xlabel('Бутстрапированные средние значения времени пребывания, сек.') plt.ylabel('Частота')  plt.show()

Приведенный выше пример наглядно показывает результаты на гистограмме:

Гистограмма демонстрирует то, как средние значения изменялись вместе с многократными выборками, взятыми из времени пребывания на обновленном веб-сайте. Хотя на входе имелась лишь одна выборка, состоящая из 16 посетителей, бутстрапированные выборки очень четко просимулировали стандартную ошибку изначальной выборки и позволили визуализировать интервал уверенности (между 78 и 165 сек.), вычисленный ранее в результате одновыборочного t-теста.

Благодаря бутстрапированию мы просимулировали взятие многократных выборок, при том, что у нас на входе имелась всего одна выборка. Этот метод обычно применяется для оценивания параметров, которые мы не способны или не знаем, как вычислить аналитически.

Проверка многочисленных вариантов дизайна

Было разочарованием обнаружить отсутствие статистической значимости на фоне увеличенного времени пребывания пользователей на обновленном веб-сайте. Хотя хорошо, что мы обнаружили это на малой выборке пользователей, прежде чем выкладывать его на всеобщее обозрение.

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

Вычисление выборочных средних

Веб-команда разворачивает 19 вариантов дизайна обновленного веб-сайта наряду с изначальным. Как отмечалось ранее, каждый вариант дизайна получает случайные 5% посетителей, и при этом наше испытание проводится в течение 24 часов.

На следующий день мы получаем файл, показывающий значения времени пребывания посетителей на каждом варианте веб-сайта. Все они были промаркированы числами, при этом число 0 соответствовало веб-сайту с исходным дизайном, а числа от 1 до 19 представляли другие варианты дизайна:

def ex_2_20(): df = load_data('multiple-sites.tsv') return df.groupby('site').aggregate(sp.mean)

Этот пример сгенерирует следующую ниже таблицу:

site

dwell-time

0

79.851064

1

106.000000

2

88.229167

3

97.479167

4

94.333333

5

102.333333

6

144.192982

7

123.367347

8

94.346939

9

89.820000

10

129.952381

11

96.982143

12

80.950820

13

90.737705

14

74.764706

15

119.347826

16

86.744186

17

77.891304

18

94.814815

19

89.280702

Мы хотели бы проверить каждый вариант дизайна веб-сайта, чтобы увидеть, не генерирует ли какой-либо из них статистически значимый результат. Для этого можно сравнить варианты дизайна веб-сайта друг с другом следующим образом, причем нам потребуется вспомогательный модуль Python itertools, который содержит набор функций, создающих итераторы для эффективной циклической обработки:

import itertoolsdef ex_2_21(): '''Проверка вариантов дизайна веб-сайта на основе t-теста по принципу "каждый с каждым"''' groups = load_data('multiple-sites.tsv').groupby('site') alpha = 0.05 pairs = [list(x) # найти сочетания из n по k for x in itertools.combinations(range(len(groups)), 2)]  for pair in pairs: gr, gr2 = groups.get_group( pair[0] ), groups.get_group( pair[1] ) site_a, site_b = pair[0], pair[1] a, b = gr['dwell-time'], gr2['dwell-time']  p_val = stats.ttest_ind(a, b, equal_var = False).pvalue  if p_val < alpha:  print('Варианты веб-сайта %i и %i значимо различаются: %f'  % (site_a, site_b, p_val))

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

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

def ex_2_22(): groups = load_data('multiple-sites.tsv').groupby('site') alpha = 0.05  baseline = groups.get_group(0)['dwell-time'] for site_a in range(1, len(groups)): a = groups.get_group( site_a )['dwell-time'] p_val = stats.ttest_ind(a, baseline, equal_var = False).pvalue  if p_val < alpha:  print('Вариант %i веб-сайта значимо отличается: %f'  % (site_a, p_val))

В результате этой проверки будут идентифицированы два варианта дизайна веб-сайта, которые существенно отличаются:

Вариант 6 веб-сайта значимо отличается: 0.005534Вариант 10 веб-сайта 10 значимо отличается: 0.006881

Малые p-значения (меньше 1%) указывают на то, что существует статистически очень значимые расхождения. Этот результат представляется весьма многообещающим, однако тут есть одна проблема. Мы выполнили t-тест по 20 выборкам данных с уровнем значимости , равным 0.05. Уровень значимости определяется, как вероятность неправильного отказа от нулевой гипотезы. На самом деле после 20-кратного выполнения t-теста становится вероятным, что мы неправильно отклоним нулевую гипотезу по крайней мере для одного варианта веб-сайта из 20.

Сравнивая таким одновременным образом многочисленные страницы, мы делаем результаты t-теста невалидными. Существует целый ряд альтернативных технических приемов решения проблемы выполнения многократных сравнений в статистических тестах. Эти методы будут рассмотрены в следующем разделе.

Поправка Бонферрони

Для проведения многократных проверок используется подход, который объясняет увеличенную вероятность обнаружить значимый эффект в силу многократных испытаний. Поправка Бонферрони это очень простая корректировка, которая обеспечивает, чтобы мы вряд ли совершили ошибки 1-го рода. Она выполняется путем настройки значения уровня значимости для тестов.

Настройка очень простая поправка Бонферрони попросту делит требуемое значение на число тестов. Например, если для теста имелось kвариантов дизайна веб-сайта, и эксперимента равно 0.05, то поправка Бонферрони выражается следующим образом:

=\frac{0.05}{k}

Она представляет собой безопасный способ смягчить увеличение вероятности совершения ошибки 1-го рода при многократной проверке. Следующий пример идентичен примеру ex-2-22, за исключением того, что значение разделено на число групп:

def ex_2_23(): '''Проверка вариантов дизайна веб-сайта на основе t-теста против исходного (0) с поправкой Бонферрони''' groups = load_data('multiple-sites.tsv').groupby('site') alpha = 0.05 / len(groups) baseline = groups.get_group(0)['dwell-time'] for site_a in range(1, len(groups)): a = groups.get_group(site_a)['dwell-time'] p_val = stats.ttest_ind(a, baseline, equal_var = False).pvalue  if p_val < alpha:  print('Вариант %i веб-сайта значимо отличается от исходного: %f'  % (site_a, p_val))

Если вы выполните приведенный выше пример, то увидите, что при использовании поправки Бонферрони ни один из веб-сайтов больше не считается статистически значимым.

Метод проверки статистической значимости связан с поддержанием равновесия чем меньше шансы совершения ошибки 1-го рода, тем больше риск совершения ошибки 2-го рода. Поправка Бонферрони очень консервативна, и весьма возможно, что из-за излишней осторожности мы пропускаем подлинное расхождение.

Примеры исходного кода для этого поста находятся в моемрепона Github. Все исходные данные взяты врепозиторииавтора книги.

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

Подробнее..

Python, корреляция и регрессия часть 1

18.05.2021 14:13:42 | Автор: admin

Чем больше я узнаю людей, тем больше мне нравится моя собака.

Марк Твен

В предыдущих сериях постов из ремикса книги Генри Гарнера Clojure для исследования данных (Clojure for Data Science) на языке Python мы рассмотрели методы описания выборок с точки зрения сводных статистик и методов статистического вывода из них параметров популяции. Такой анализ сообщает нам нечто о популяции в целом и о выборке в частности, но он не позволяет нам делать очень точные утверждения об их отдельных элементах. Это связано с тем, что в результате сведения данных всего к двум статистикам - среднему значению и стандартному отклонению - теряется огромный объем информации.

Нам часто требуется пойти дальше и установить связь между двумя или несколькими переменными либо предсказать одну переменную при наличии другой. И это подводит нас к теме данной серии из 5 постов - исследованию корреляции и регрессии. Корреляция имеет дело с силой и направленностью связи между двумя или более переменными. Регрессия определяет природу этой связи и позволяет делать предсказания на ее основе.

В этой серии постов будет рассмотрена линейная регрессия. При наличии выборки данных наша модель усвоит линейное уравнение, позволяющее ей делать предсказания о новых, не встречавшихся ранее данных. Для этого мы снова обратимся к библиотеке pandas и изучим связь между ростом и весом спортсменов-олимпийцев. Мы введем понятие матриц и покажем способы управления ими с использованием библиотеки pandas.

О данных

В этой серии постов используются данные, любезно предоставленные компанией Guardian News and Media Ltd., о спортсменах, принимавших участие в Олимпийских Играх 2012 г. в Лондоне. Эти данные изначально были взяты из блога газеты Гардиан.

Обследование данных

Когда вы сталкиваетесь с новым набором данных, первая задача состоит в том, чтобы его обследовать с целью понять, что именно он содержит.

Файл all-london-2012-athletes.tsv достаточно небольшой. Мы можем обследовать данные при помощи pandas, как мы делали в первой серии постов Python, исследование данных и выборы, воспользовавшись функцией read_csv:

def load_data(): return pd.read_csv('data/ch03/all-london-2012-athletes-ru.tsv', '\t') def ex_3_1(): '''Загрузка данных об участниках  олимпийских игр в Лондоне 2012 г.''' return load_data()

Если выполнить этот пример в консоли интерпретатора Python либо в блокноте Jupyter, то вы должны увидеть следующий ниже результат:

Столбцы данных (нам повезло, что они ясно озаглавлены) содержат следующую информацию:

  • ФИО атлета

  • страна, за которую он выступает

  • возраст, лет

  • рост, см.

  • вес, кг.

  • пол "М" или "Ж"

  • дата рождения в виде строки

  • место рождения в виде строки (со страной)

  • число выигранных золотых медалей

  • число выигранных серебряных медалей

  • число выигранных бронзовых медалей

  • всего выигранных золотых, серебряных и бронзовых медалей

  • вид спорта, в котором он соревновался

  • состязание в виде списка, разделенного запятыми

Даже с учетом того, что данные четко озаглавлены, очевидно присутствие пустых мест в столбцах с ростом, весом и местом рождения. При наличии таких данных следует проявлять осторожность, чтобы они не сбили с толку.

Визуализация данных

В первую очередь мы рассмотрим разброс роста спортсменов на Олимпийских играх 2012 г. в Лондоне. Изобразим эти значения роста в виде гистограммы, чтобы увидеть характер распределения данных, не забыв сначала отфильтровать пропущенные значения:

def ex_3_2(): '''Визуализация разброса значений  роста спортсменов на гистограмме''' df = load_data() df['Рост, см'].hist(bins=20) plt.xlabel('Рост, см.') plt.ylabel('Частота') plt.show()

Этот пример сгенерирует следующую ниже гистограмму:

Как мы и ожидали, данные приближенно нормально распределены. Средний рост спортсменов составляет примерно 177 см. Теперь посмотрим на распределение веса олимпийских спортсменов:

def ex_3_3(): '''Визуализация разброса значений веса спортсменов''' df = load_data() df['Вес'].hist(bins=20) plt.xlabel('Вес') plt.ylabel('Частота') plt.show()

Приведенный выше пример сгенерирует следующую ниже гистограмму:

Данные показывают четко выраженную асимметрию. Хвост с правой стороны намного длиннее, чем с левой, и поэтому мы говорим, что асимметрия - положительная. Мы можем оценить асимметрию данных количественно при помощи функции библиотеки pandas skew:

def ex_3_4(): '''Вычисление асимметрии веса спортсменов''' df = load_data() swimmers = df[ df['Вид спорта'] == 'Swimming'] return swimmers['Вес'].skew()
0.23441459903001483

К счастью, эта асимметрия может быть эффективным образом смягчена путем взятия логарифма веса при помощи функции библиотеки numpy np.log:

def ex_3_5(): '''Визуализация разброса значений веса спортсменов на полулогарифмической гистограмме с целью удаления  асимметрии''' df = load_data() df['Вес'].apply(np.log).hist(bins=20) plt.xlabel('Логарифмический вес') plt.ylabel('Частота') plt.show()

Этот пример сгенерирует следующую ниже гистограмму:

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

Логнормальное распределение

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

Логарифм показывает степень, в которую должно быть возведено фиксированное число (основание) для получения данного числа. Изобразив логарифмы на графике в виде гистограммы, мы показали, что эти степени приближенно нормально распределены. Логарифмы обычно берутся по основанию 10 или основанию e, трансцендентному числу, приближенно равному 2.718. В функции библиотеки numpy np.log и ее инверсии np.exp используется основание e. Выражение loge также называется натуральным логарифмом, или ln, из-за свойств, делающих его особенно удобным в исчислении.

Логнормальное распределение обычно имеет место в процессах роста, где темп роста не зависит от размера. Этот феномен известен как закон Джибрэта, который был cформулирован в 1931 г. Робертом Джибрэтом, заметившим, что он применим к росту фирм. Поскольку темп роста пропорционален размеру, более крупные фирмы демонстрируют тенденцию расти быстрее, чем фирмы меньшего размера.

Нормальное распределение случается в ситуациях, где много мелких колебаний, или вариаций, носит суммирующий эффект, тогда как логнормальное распределение происходит там, где много мелких вариаций имеет мультипликативный эффект.

С тех пор выяснилось, что закон Джибрэта применим к большому числу ситуаций, включая размеры городов и, согласно обширному математическому ресурсу Wolfram MathWorld, к количеству слов в предложениях шотландского писателя Джорджа Бернарда Шоу.

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

Визуализация корреляции

Один из самых быстрых и самых простых способов определить наличие корреляции между двумя переменными состоит в том, чтобы рассмотреть их на графике рассеяния. Мы отфильтруем данные, выбрав только пловцов, и затем построим график роста относительно веса спортсменов:

def swimmer_data(): '''Загрузка данных роста и веса только олимпийских пловцов''' df = load_data() return df[df['Вид спорта'] == 'Swimming'].dropna()def ex_3_6(): '''Визуализация корреляции между ростом и весом''' df = swimmer_data() xs = df['Рост, см'] ys = df['Вес'].apply( np.log ) pd.DataFrame(np.array([xs,ys]).T).plot.scatter(0, 1, s=12, grid=True) plt.xlabel('Рост, см.') plt.ylabel('Логарифмический вес') plt.show()

Этот пример сгенерирует следующий ниже график:

Результат ясно показывает, что между этими двумя переменными имеется связь. График имеет характерно смещенную эллиптическую форму двух коррелируемых, нормально распределенных переменных с центром вокруг среднего значения. Следующая ниже диаграмма сравнивает график рассеяния с распределениями вероятностей роста и логарифма веса:

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

Генерирование джиттера

Поскольку каждое значение округлено до ближайшего сантиметра или килограмма, то значение, записанное как 180 см, на самом деле может быть каким угодно между 179.5 и 180.5 см, тогда как значение 80 кг на самом деле может быть каким угодно между 79.5 и 80.5 кг. Для создания случайных искажений, мы можем добавить случайные помехи в каждую точку данных роста в диапазоне между -0.5 и 0.5 и в том же самом диапазоне проделать с точками данных веса (разумеется, это нужно cделать до того, как мы возьмем логарифм значений веса):

def jitter(limit): '''Генератор джиттера (произвольного сдвига точек данных)''' return lambda x: random.uniform(-limit, limit) + xdef ex_3_7(): '''Визуализация корреляции между ростом и весом с джиттером''' df = swimmer_data() xs = df['Рост, см'].apply(jitter(0.5)) ys = df['Вес'].apply(jitter(0.5)).apply(np.log) pd.DataFrame(np.array([xs,ys]).T).plot.scatter(0, 1, s=12, grid=True) plt.xlabel('Рост, см.') plt.ylabel('Логарифмический вес') plt.show()

График с джиттером выглядит следующим образом:

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

Ковариация

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

Если у нас имеется два ряда чисел, X и Y, то их отклонения от среднего значения составляют:

dx_i= x_i-x dy_i=y_i-y

Здесь xi это значение X с индексом i, yi значение Y с индексом i, x среднее значение X, и y среднее значение Y. Если X и Y проявляют тенденцию изменяться вместе, то их отклонения от среднего будет иметь одинаковый знак: отрицательный, если они меньше среднего, положительный, если они больше среднего. Если мы их перемножим, то произведение будет положительным, когда у них одинаковый знак, и отрицательным, когда у них разные знаки. Сложение произведений дает меру тенденции этих двух переменных отклоняться от среднего значения в одинаковом направлении для каждой заданной выборки.

Ковариация определяется как среднее этих произведений:

На чистом Python ковариация вычисляется следующим образом:

def covariance(xs, ys): '''Вычисление ковариации (несмещенная, т.е. n-1)''' dx = xs - xs.mean()  dy = ys - ys.mean() return (dx * dy).sum() / (dx.count() - 1)

В качестве альтернативы, мы можем воспользоваться функцией pandas cov:

df['Рост, см'].cov(df['Вес'])
1.3559273321696459

Ковариация роста и логарифма веса для наших олимпийских пловцов равна 1.356, однако это число сложно интерпретировать. Единицы измерения здесь представлены произведением единиц на входе.

По этой причине о ковариации редко сообщают как об отдельной сводной статистике. Сделать число более понятным можно, разделив отклонения на произведение стандартных отклонений. Это позволяет трансформировать единицы измерения в стандартные оценки и ограничить выход числом в диапазоне между -1 и +1. Этот результат называется корреляцией Пирсона.

Стандартная оценка, англ. standard score, также z-оценка это относительное число стандартных отклонений, на которые значение переменной отстоит от среднего значения. Положительная оценка показывает, что переменная находится выше среднего, отрицательная ниже среднего. Это безразмерная величина, получаемая при вычитании популяционного среднего из индивидуальных значений и деления разности на популяционное стандартное отклонение.

Корреляция Пирсона

Корреляция Пирсона часто обозначается переменной rи вычисляется следующим образом, где отклонения от среднего dxiи dyiвычисляются как и прежде:

Поскольку для переменных X и Y стандартные отклонения являются константными, уравнение может быть упрощено до следующего, где xи y это стандартные отклонения соответственно X и Y:

В таком виде формула иногда упоминается как коэффициент корреляции смешанных моментов Пирсона или попросту коэффициент корреляции и, как правило, обозначается буквой r.

Ранее мы уже написали функции для вычисления стандартного отклонения. В сочетании с нашей функцией с вычислением ковариации получится следующая реализация корреляции Пирсона:

def variance(xs): '''Вычисление корреляции, несмещенная дисперсия при n <= 30''' x_hat = xs.mean() n = xs.count() n = n - 1 if n in range( 1, 30 ) else n  return sum((xs - x_hat) ** 2) / ndef standard_deviation(xs): '''Вычисление стандартного отклонения''' return np.sqrt(variance(xs))def correlation(xs, ys):  '''Вычисление корреляции''' return covariance(xs, ys) / (standard_deviation(xs) *  standard_deviation(ys))

В качестве альтернативы мы можем воспользоваться функцией pandas corr:

df['Рост, см'].corr(df['Вес'])

Поскольку стандартные оценки безразмерны, то и коэффициент корреляции rтоже безразмерен. Если rравен -1.0 либо 1.0, то переменные идеально антикоррелируют либо идеально коррелируют.

Правда, если r = 0, то с необходимостью вовсе не следует, что переменные не коррелируют. Корреляция Пирсона измеряет лишь линейные связи. Как продемонстрировано на следующих графиках, между переменными может существовать еще некая нелинейная связь, которую rне объясняет:

Отметим, что корреляция центрального примера не определена, потому что стандартное отклонение y = 0. Поскольку наше уравнение для rсодержало бы деление ковариации на 0, то результат получается бессмысленным. В этом случае между переменными не может быть никакой корреляции; yвсегда будет иметь среднее значение. Простое обследование стандартных отклонений это подтвердит.

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

def ex_3_8(): '''Вычисление корреляции средствами pandas на примере данных роста и веса''' df = swimmer_data() return df['Рост, см'].corr( df['Вес'].apply(np.log))
0.86748249283924894

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

Выборочный rи популяционный

Аналогично среднему значению и стандартному отклонению, коэффициент корреляции является сводной статистикой. Он описывает выборку; в данном случае, выборку спаренных значений: роста и веса. Коэффициент корреляции известной выборки обозначается буквой r, тогда как коэффициент корреляции неизвестной популяции обозначается греческой буквой (рхо).

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

Даже в допустимой популяции такой как пловцы, выступавшие на недавних Олимпийских играх, наша выборка коэффициента корреляции является всего лишь одной из многих потенциально возможных. То, насколько мы можем доверять нашему r, как оценке параметра , зависит от двух факторов:

  • Размера выборки

  • Величины r

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

Проверка статистических гипотез

В предыдущей серии постов мы познакомились с проверкой статистических гипотез, как средством количественной оценки вероятности, что конкретная гипотеза (как, например, что две выборки взяты из одной и той же популяции) истинная. Чтобы количественно оценить вероятность, что корреляция существует в более широкой популяции, мы воспользуемся той же самой процедурой.

В первую очередь, мы должны сформулировать две гипотезы, нулевую гипотезу и альтернативную:

H_0=0H_1\ne 0

H0 - это гипотеза, что корреляция в популяции нулевая. Другими словами, наше консервативное представление состоит в том, что измеренная корреляция целиком вызвана случайной ошибкой при отборе.

H1 - это альтернативная возможность, что корреляция в популяции не нулевая. Отметим, что мы не определяем направление корреляции, а только что она существует. Это означает, что мы выполняем двустороннюю проверку.

Стандартная ошибка коэффициента корреляции rпо выборке задается следующей формулой:

Эта формула точна, только когда rнаходится близко к нулю (напомним, что величина влияет на нашу уверенность), но к счастью, это именно то, что мы допускаем согласно нашей нулевой гипотезы.

Мы можем снова воспользоваться t-распределением и вычислить t-статистику:

В приведенной формуле df это степень свободы наших данных. Для проверки корреляции степень свободы равна n - 2, где n это размер выборки. Подставив это значение в формулу, получим:

В итоге получим t-значение 102.21. В целях его преобразования в p-значение мы должны обратиться к t-распределению. Библиотека scipy предоставляет интегральную функцию распределения (ИФР) для t-распределения в виде функции stats.t.cdf, и комплементарной ей (1-cdf) функции выживания stats.t.sf. Значение функции выживания соответствует p-значению для односторонней проверки. Мы умножаем его на 2, потому что выполняем двустороннюю проверку:

def t_statistic(xs, ys): '''Вычисление t-статистики''' r = xs.corr(ys) # как вариант, correlation(xs, ys) df = xs.count() - 2 return r * np.sqrt(df / 1 - r ** 2)def ex_3_9(): '''Выполнение двухстороннего t-теста''' df = swimmer_data() xs = df['Рост, см'] ys = df['Вес'].apply(np.log) t_value = t_statistic(xs, ys) df = xs.count() - 2  p = 2 * stats.t.sf(t_value, df) # функция выживания  return {'t-значение':t_value, 'p-значение':p}
{'p-значение': 1.8980236317815443e-106, 't-значение': 25.384018200627057}

P-значение настолько мало, что в сущности равно 0, означая, что шанс, что нулевая гипотеза является истинной, фактически не существует. Мы вынуждены принять альтернативную гипотезу о существовании корреляции.

Интервалы уверенности

Установив, что в более широкой популяции, безусловно, существует корреляция, мы, возможно, захотим количественно выразить диапазон значений, внутри которого, как мы ожидаем, будет лежать параметр , вычислив для этого интервал уверенности. Как и в случае со средним значением в предыдущей серии постов, интервал уверенности для rвыражает вероятность (выраженную в %), что параметр популяции находится между двумя конкретными значениями.

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

Приведенный выше график показывает отрицательно скошенное распределение r-выборок для параметра , равного 0.6.

К счастью, трансформация под названием z-преобразование Фишера стабилизирует дисперсию r по своему диапазону. Она аналогична тому, как наши данные о весе спортсменов стали нормально распределенными, когда мы взяли их логарифм.

Уравнение для z-преобразования следующее:

Стандартная ошибка z равна:

Таким образом, процедура вычисления интервалов уверенности состоит в преобразовании rв z с использованием z-преобразования, вычислении интервала уверенности в терминах стандартной ошибки SEzи затем преобразовании интервала уверенности в r.

В целях вычисления интервала уверенности в терминах SEz, мы можем взять число стандартных отклонений от среднего, которое дает нам требуемый уровень доверия. Обычно используют число 1.96, так как оно является числом стандартных отклонений от среднего, которое содержит 95% площади под кривой. Другими словами, 1.96 стандартных ошибок от среднего значения выборочного rсодержит истинную популяционную корреляцию с 95%-ой определенностью.

Мы можем убедиться в этом, воспользовавшись функцией scipy stats.norm.ppf. Она вернет стандартную оценку, связанную с заданной интегральной вероятностью в условиях односторонней проверки.

Однако, как показано на приведенном выше графике, мы хотели бы вычесть ту же самую величину, т.е. 2.5%, из каждого хвоста с тем, чтобы 95%-й интервал уверенности был центрирован на нуле. Для этого при выполнении двусторонней проверки нужно просто уменьшить разность наполовину и вычесть результат из 100%. Так что, требуемый уровень доверия в 95% означает, что мы обращаемся к критическому значению 97.5%:

def critical_value(confidence, ntails): # ДИ и число хвостов '''Расчет критического значения путем вычисления квантиля и получения  для него нормального значения''' lookup = 1 - ((1 - confidence) / ntails)  return stats.norm.ppf(lookup, 0, 1) # mu=0, sigma=1critical_value(0.95, 2)
1.959963984540054

Поэтому наш 95%-й интервал уверенности в z-пространстве для задается следующей формулой:

Подставив в нашу формулу zrи SEz, получим:

Для r=0.867и n=859она даст нижнюю и верхнюю границу соответственно 1.137 и 1.722. В целях их преобразования из z-оценок в r-значения, мы используем следующее обратное уравнение z-преобразования:

Преобразования и интервал уверенности можно вычислить при помощи следующего исходного кода:

def z_to_r(z): '''Преобразование z-оценки обратно в r-значение''' return (np.exp(z*2) - 1) / (np.exp(z*2) + 1)def r_confidence_interval(crit, xs, ys):  '''Расчет интервала уверенности для критического значения и данных''' r = xs.corr(ys) n = xs.count() zr = 0.5 * np.log((1 + r) / (1 - r))  sez = 1 / np.sqrt(n - 3) return (z_to_r(zr - (crit * sez))), (z_to_r(zr + (crit * sez)))def ex_3_10(): '''Расчет интервала уверенности на примере данных роста и веса''' df = swimmer_data() X = df['Рост, см'] y = df['Вес'].apply(np.log) interval = r_confidence_interval(1.96, X, y)  print('Интервал уверенности (95%):', interval)
Интервал уверенности (95%): (0.8499088588880347, 0.8831284878884087)

В результате получаем 95%-й интервал уверенности для , расположенный между 0.850 и 0.883. Мы можем быть абсолютно уверены в том, что в более широкой популяции олимпийских пловцов существует сильная положительная корреляция между ростом и весом.

В следующем посте, посте 2, будет рассмотрена сама тема серии постов - регрессия и приемы оценивания ее качества.

Подробнее..

Python, корреляция и регрессия часть 2

18.05.2021 20:09:49 | Автор: admin

Предыдущий пост см. здесь.

Регрессия

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

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

Описываемые этими уравнениями линии называются линиями регрессии. Этот Термин был введен британским эрудитом 19-ого века сэром Фрэнсисом Гэлтоном. Он и его студент Карл Пирсон, который вывел коэффициент корреляции, в 19-ом веке разработали большое количество методов, применяемых для изучения линейных связей, которые коллективно стали известны как методы регрессионного анализа.

Вспомним, что из корреляции не следует причинная обусловленность, причем термины зависимый и независимый не означают никакой неявной причинной обусловленности. Они представляют собой всего лишь имена для входных и выходных математических значений. Классическим примером является крайне положительная корреляция между числом отправленных на тушение пожара пожарных машин и нанесенным пожаром ущербом. Безусловно, отправка пожарных машин на тушение пожара сама по себе не наносит ущерб. Никто не будет советовать сократить число машин, отправляемых на тушение пожара, как способ уменьшения ущерба. В подобных ситуациях мы должны искать дополнительную переменную, которая была бы связана с другими переменными причинной связью и объясняла корреляцию между ними. В данном примере это может быть размер пожара. Такие скрытые причины называются спутывающими переменными, потому что они искажают нашу возможность определять связь между зависимыми переменными.

Линейные уравнения

Две переменные, которые мы можем обозначить как xи y, могут быть связаны друг с другом строго или нестрого. Самая простая связь между независимой переменной xи зависимой переменной yявляется прямолинейной, которая выражается следующей формулой:

y=a+bx

Здесь значения параметров aи bопределяют соответственно точную высоту и крутизну прямой. Параметр aназывается пересечением с вертикальной осью или константой, а b градиентом, наклоном линии или угловым коэффициентом. Например, в соотнесенности между температурными шкалами по Цельсию и по Фаренгейту a = 32и b = 1.8. Подставив в наше уравнение значения aи b, получим:

y=32+1.8x

Для вычисления 10С по Фаренгейту мы вместо xподставляем 10:

y=32+1.8(10)=50

Таким образом, наше уравнение сообщает, что 10С равно 50F, и это действительно так. Используя Python и возможности визуализации pandas, мы можем легко написать функцию, которая переводит градусы из Цельсия в градусы Фаренгейта и выводит результат на график:

'''Функция перевода из градусов Цельсия в градусы Фаренгейта'''celsius_to_fahrenheit = lambda x: 32 + (x * 1.8)def ex_3_11(): '''График линейной зависимости температурных шкал''' df = pd.DataFrame({'C':s, 'F':s.map(celsius_to_fahrenheit)}) df.plot('C', 'F', legend=False, grid=True) plt.xlabel('Градусы Цельсия') plt.ylabel('Градусы Фаренгейта') plt.show()

Этот пример сгенерирует следующий ниже линейный график:

Обратите внимание, как синяя линия пересекает 0 на шкале Цельсия при величине 32 на шкале Фаренгейта. Пересечение a это значение y, при котором значение xравно 0.

Наклон линии с неким угловым коэффициентом определяется параметром b; в этом уравнении его значение близко к 2. Как видно, диапазон шкалы Фаренгейта почти вдвое шире диапазона шкалы Цельсия. Другими словами, прямая устремляется вверх по вертикали почти вдвое быстрее, чем по горизонтали.

Остатки

К сожалению, немногие связи столь же чистые, как перевод между градусами Цельсия и Фаренгейта. Прямолинейное уравнение редко позволяет нам определять yстрого в терминах x. Как правило, будет иметься ошибка, и, таким образом, уравнение примет следующий вид:

y=a+bx+

Здесь, это ошибка или остаточный член, обозначающий расхождение между значением, вычисленным параметрами aи bдля данного значения xи фактическим значением y. Если предсказанное значение y это y, то ошибка это разность между обоими:

=y-y

Такая ошибка называется остатком. Остаток может возникать из-за случайных факторов, таких как погрешность измерения, либо неслучайных факторов, которые неизвестны. Например, если мы пытаемся предсказать вес как функцию роста, то неизвестные факторы могут состоять из диеты, уровня физической подготовки и типа телосложения (либо просто эффекта округления до самого близкого килограмма).

Если для aи bмы выберем неидеальные параметры, то остаток для каждого xбудет больше, чем нужно. Из этого следует, что параметры, которые мы бы хотели найти, должны минимизировать остатки во всех значениях xи y.

Обычные наименьшие квадраты

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

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

Выражаясь в терминах задачи оптимизации, мы стремимся выявить коэффициенты, которые минимизируют сумму квадратов остатков. Этот метод называется обычными наименьшими квадратами, от англ. Ordinary Least Squares (OLS), и формула для вычисления наклона линии регрессии по указанному методу выглядит так:

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

Пересечение (a) это член, позволяющий прямой с заданным наклоном проходить через среднее значение X и Y:

a=y -bx

Значения aи b это коэффициенты, получаемые в результате оценки методом обычных наименьших квадратов.

Наклон и пересечение

Мы уже рассматривали функции covariance, variance и mean, которые нужны для вычисления наклона прямой и точки пересечения для данных роста и веса пловцов. Поэтому вычисление наклона и пересечения имеют тривиальный вид:

def slope(xs, ys): '''Вычисление наклона линии (углового коэффициента)''' return xs.cov(ys) / xs.var()def intercept(xs, ys):  '''Вычисление точки пересечения (с осью Y)''' return ys.mean() - (xs.mean() * slope(xs, ys))def ex_3_12(): '''Вычисление пересечения и наклона (углового коэффициента)  на примере данных роста и веса''' df = swimmer_data() X = df['Рост, см'] y = df['Вес'].apply(np.log) a = intercept(X, y) b = slope(X, y)  print('Пересечение: %f, наклон: %f' % (a,b))
Пересечение: 1.691033, наклон: 0.014296

В результате будет получен наклон приблизительно 0.0143 и пересечение приблизительно 1.6910.

Интерпретация

Величина пересечения это значение зависимой переменной (логарифмический вес), когда независимая переменная (рост) равна нулю. Для получения этого значения в килограммах мы можем воспользоваться функцией np.exp, обратной для функции np.log. Наша модель дает основания предполагать, что вероятнее всего вес олимпийского пловца с нулевым ростом будет 5.42 кг. Разумеется, такое предположение лишено всякого смысла, к тому же экстраполяция за пределы границ тренировочных данных является не самым разумным решением.

Величина наклона показывает, насколько yизменяется для каждой единицы изменения в x. Модель исходит из того, что каждый дополнительный сантиметр роста прибавляет в среднем 1.014 кг. веса олимпийских пловцов. Поскольку наша модель основывается на данных о всех олимпийских пловцах, она представляет собой усредненный эффект от увеличения в росте на единицу без учета любого другого фактора, такого как возраст, пол или тип телосложения.

Визуализация

Результат линейного уравнения можно визуализировать при помощи имплементированной ранее функции regression_line и простой функции от x, которая вычисляет yна основе коэффициентов aи b.

'''Функция линии регрессии'''regression_line = lambda a, b: lambda x: a + (b * x) # вызовы fn(a,b)(x)def ex_3_13(): '''Визуализация линейного уравнения на примере данных роста и веса''' df = swimmer_data() X = df['Рост, см'].apply( jitter(0.5) ) y = df['Вес'].apply(np.log) a, b = intercept(X, y), slope(X, y)  ax = pd.DataFrame(np.array([X, y]).T).plot.scatter(0, 1, s=7) s = pd.Series(range(150,210)) df = pd.DataFrame( {0:s, 1:s.map(regression_line(a, b))} )  df.plot(0, 1, legend=False, grid=True, ax=ax) plt.xlabel('Рост, см.') plt.ylabel('Логарифмический вес') plt.show()

Функция regression_line возвращает функцию от x, которая вычисляет a + bx.

Указанная функция может также использоваться для вычисления каждого остатка, показывая степень, с которой наша оценка yотклоняется от каждого измеренного значения y.

def residuals(a, b, xs, ys): '''Вычисление остатков''' estimate = regression_line(a, b) # частичное применение return pd.Series( map(lambda x, y: y - estimate(x), xs, ys) )constantly = lambda x: 0def ex_3_14(): '''Построение графика остатков на примере данных роста и веса''' df = swimmer_data() X = df['Рост, см'].apply( jitter(0.5) ) y = df['Вес'].apply(np.log) a, b = intercept(X, y), slope(X, y)  y = residuals(a, b, X, y) ax = pd.DataFrame(np.array([X, y]).T).plot.scatter(0, 1, s=12) s = pd.Series(range(150,210)) df = pd.DataFrame( {0:s, 1:s.map(constantly)} )  df.plot(0, 1, legend=False, grid=True, ax=ax) plt.xlabel('Рост, см.') plt.ylabel('Остатки') plt.show()

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

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

Допущения

Первостепенное допущение линейной регрессии состоит в том, что, безусловно, существует линейная зависимость между зависимой и независимой переменной. Кроме того, остатки не должны коррелировать друг с другом либо с независимой переменной. Другими словами, мы ожидаем, что ошибки будут иметь нулевое среднее и постоянную дисперсию по отношению к зависимой и независимой переменной. График остатков позволяет быстро устанавливать, является ли это действительно так.

Левая сторона нашего графика имеет более крупные значения остатков, чем правая сторона. Это соответствует большей дисперсии веса среди более низкорослых спортсменов. Когда дисперсия одной переменной изменяется относительно другой, говорят, что переменные гетероскедастичны, т.е. их дисперсия неоднородна. Этот факт представляет в регрессионном анализе проблему, потому что делает не валидным допущение в том, что модельные ошибки не коррелируют и нормально распределены, и что их дисперсии не варьируются вместе с моделируемыми эффектами.

Гетероскедастичность остатков здесь довольно мала и особо не должна повлиять на качество нашей модели. Если дисперсия на левой стороне графика была бы более выраженной, то она привела бы к неправильной оценке дисперсии методом наименьших квадратов, что в свою очередь повлияло бы на выводы, которые мы делаем, основываясь на стандартной ошибке.

Качество подгонки и R-квадрат

Хотя из графика остатков видно, что линейная модель хорошо вписывается в данные, т.е. хорошо к ним подогнана, было бы желательно количественно измерить качество этой подгонки. R2, или R-квадрат, варьируется в интервале между 0 и 1 и обозначает объяснительную мощность линейной регрессионной модели. Он вычисляет объясненную долю изменчивости в зависимой переменной.

Обычно, чем ближе R2к 1, тем лучше линия регрессии подогнана к точкам данных и больше изменчивости в Y объясняется независимой переменной X. R2 можно вычислить с помощью следующей ниже формулы:

Здесь var() это дисперсия остатков и var(Y) дисперсия в Y. В целях понимания смысла этой формулы допустим, что вы пытаетесь угадать чей-то вес. Если вам больше ничего неизвестно об испытуемых, то наилучшей стратегией будет угадывать среднее значение весовых данных внутри популяции в целом. Таким путем средневзвешенная квадратичная ошибка вашей догадки в сравнении с истинным весом будет var(Y), т.е. дисперсией данных веса в популяции.

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

Компонент формулы var()/var(Y) это соотношение средневзвешенной квадратичной ошибки с объяснительной переменной и без нее, т. е. доля изменчивости, оставленная моделью без объяснения. Дополнение R2до единицы это доля изменчивости, объясненная моделью.

Как и в случае с r, низкий R2не означает, что две переменные не коррелированы. Просто может оказаться, что их связь не является линейной.

Значение R2 описывает качество подгонки линии регрессии к данным. Оптимально подогнанная линия это линия, которая минимизирует значение R2. По мере удаления либо приближения от своих оптимальных значений R2 всегда будет расти.

Левый график показывает дисперсию модели, которая всегда угадывает среднее значение для , правый же показывает меньшие по размеру квадраты, связанные с остатками, которые остались необъясненными моделью f. С чисто геометрической точки зрения можно увидеть, как модель объяснила большинство дисперсии в y. Приведенный ниже пример вычисляет R2путем деления дисперсии остатков на дисперсию значений y:

def r_squared(a, b, xs, ys): '''Рассчитать коэффициент детерминации (R-квадрат)''' r_var = residuals(a, b, xs, ys).var()  y_var = ys.var() return 1 - (r_var / y_var)def ex_3_15(): '''Рассчитать коэффициент R-квадрат  на примере данных роста и веса''' df = swimmer_data() X = df['Рост, см'].apply( jitter(0.5) ) y = df['Вес'].apply(np.log) a, b = intercept(X, y), slope(X, y) return r_squared(a, b, X, y)
0.75268223613272323

В результате получим значение 0.753. Другими словами, более 75% дисперсии веса пловцов, выступавших на Олимпийских играх 2012 г., можно объяснить ростом.

В случае простой регрессионной модели (с одной независимой переменной), связь между коэффициентом детерминации R2 и коэффициентом корреляции rявляется прямолинейной:

Коэффициент корреляции rможет означать, что половина изменчивости в переменной Y объясняется переменной X, но фактически R2 составит 0.52, т.е. 0.25.

Множественная линейная регрессия

Пока что в этой серии постов мы видели, как строится линия регрессии с одной независимой переменной. Однако, нередко желательно построить модель с несколькими независимыми переменными. Такая модель называется множественной линейной регрессией.

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

y=_1x_1+_2x_2

Такая модель эквивалентна двухфакторной линейно-регрессионной модели, где 1= a и 2= b при условии, что x1всегда гарантированно равен 1, вследствие чего 1 это всегда константная составляющая, которая представляет наше пересечение, при этом x1называется постоянным смещением уравнения регрессии, или членом смещения.

Обобщив линейное уравнение в терминах , его легко расширить на столько коэффициентов, насколько нам нужно:

y=_1x_1+_2x_2++_nx_n

Каждое значение от x1до xnсоответствует независимой переменной, которая могла бы объяснить значение y. Каждое значение от 1до nсоответствует коэффициенту, который устанавливает относительный вклад независимой переменной.

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

До настоящего момента мы предоставляли независимую переменную в виде одной последовательности значений, однако при наличии двух и более параметров нам нужно предоставлять несколько значений для каждого x. Мы можем воспользоваться функциональностью библиотеки pandas, чтобы выбрать два и более столбцов и управлять каждым как списком, но есть способ получше: матрицы.

Темой следующего поста, поста 3, будут матричные операции, нормальное уравнение и коллинеарность.

Подробнее..

Python, корреляция и регрессия часть 4

19.05.2021 12:19:31 | Автор: admin

Предыдущий пост см. здесь.

Предсказание

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

9-кратный олимпийский чемпион по плаванию Марк Шпитц завоевал 7 золотых медалей на Олимпийских играх 1972 г. Он родился в 1950 г. и, согласно веб-страницы Википедии, имеет рост 183 см. и вес 73 кг. Посмотрим, что наша модель предсказывает в отношении его веса.

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

Матрица содержит коэффициенты для каждого из этих признаков:

Предсказанием модели будет сумма произведений коэффициентов и признаков xв каждой строке:

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

Напомним, что размерность итоговой матрицы будет числом строк из первой матрицы и числом столбцов из второй матрицы:

Здесь Tx это произведение матрицы размера 1 nи матрицы размера n 1. Результатом является матрица размера 1 1:

Исходный код вычислений очень прост:

def predict(coefs, x):     '''функция предсказания'''    return np.matmul(coefs, x.values) 
def ex_3_29():    '''Вычисление ожидаемого веса спортсмена'''    df = swimmer_data()    df['бин_Пол'] = df['Пол'].map({'М': 1, 'Ж': 0}).astype(int)     df['Год рождения'] = df['Дата рождения'].map(str_to_year)    X = df[['Рост, см', 'бин_Пол', 'Год рождения']]     X.insert(0, 'константа', 1.0)    y = df['Вес'].apply(np.log)     beta = linear_model(X, y)    xspitz = pd.Series([1.0, 183, 1, 1950]) # параметры Марка Шпитца    return np.exp( predict(beta, xspitz) )  
84.20713139038605

Этот пример вернет число 84.21, которое соответствует ожидаемому весу 84.21 кг. Это намного тяжелее зарегистрированного веса Марка Шпитца 73 кг. Наша модель, похоже, не сработала как надо.

Интервал уверенности для конкретного предсказания

Ранее мы рассчитали интервалы уверенности для параметров популяции. Мы можем также построить интервал уверенности для отдельно взятого предсказания, именуемый интервалом предсказания, или интервалом изменений предсказанной величины. Интервал предсказания количественно определяет размер неопределенности в предсказании, предлагая минимальное и максимальное значение, между которыми истинное значение ожидаемо попадает с определенной вероятностью. Интервал предсказания для yшире интервала уверенности для параметра популяции, такого как например, среднее значение . Это объясняется тем, что в интервале уверенности учитывается только неопределенность при оценке среднего значения, в то время как интервал предсказания также должен принимать в расчет дисперсию в yот среднего значения.

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

Приведенный выше график показывает связь между внешним интервалом предсказания и внутренним интервалом уверенности. Мы можем вычислить интервал предсказания, используя следующую ниже формулу:

Здесь yp это предсказание, плюс или минус интервал. Мы пользуемся t-распределением, где степень свободы равна n - p, т.е. размер выборки минус число параметров. Это та же самая формула, которая ранее применялась при вычислении F-тестов. Хотя указанная формула, возможно, пугает своей сложностью, она относительно прямолинейно транслируется в исходный код, показанный в следующем ниже примере, который вычисляет 95%-ый интервал предсказания.

def prediction_interval(x, y, xp):    '''Вычисление интервала предсказания'''    xtx    = np.matmul(x.T, np.asarray(x))    xtxi   = np.linalg.inv(xtx)      xty    = np.matmul(x.T, np.asarray(y))     coefs  = linear_model(x, y)     fitted = np.matmul(x, coefs)    resid  = y - fitted    rss    = resid.dot(resid)      n      = y.shape[0]  # строки    p      = x.shape[1]  # столбцы    dfe    = n - p     mse    = rss / dfe    se_y   = np.matmul(np.matmul(xp.T, xtxi), xp)    t_stat = np.sqrt(mse * (1 + se_y))         # t-статистика    intl   = stats.t.ppf(0.975, dfe) * t_stat       yp     = np.matmul(coefs.T, xp)    return np.array([yp - intl, yp + intl])

Поскольку t-статистика параметризуется степенью свободы ошибки, она принимает в расчет присутствующую в модели неопределенность.

Если вместо интервала предсказания потребуется рассчитать интервал уверенности для среднего значения, мы попросту можем опустить прибавление единицы к se_y при вычислении t-статистики t_stat.

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

В приведенном выше графике модель тренируется на выборке из 5 элементов и показывает, как 95%-й интервал предсказания увеличивается по мере нашего движения дальше от среднего роста. Применив приведенную выше формулу к Марку Шпитцу, в результате получим следующее:

def ex_3_30():    '''Интервал предсказания       применительно к данным о Марке Шпитце'''    df = swimmer_data()    df['бин_Пол'] = df['Пол'].map({'М': 1, 'Ж': 0}).astype(int)     df['Год рождения'] = df['Дата рождения'].map(str_to_year)    X = df[['Рост, см', 'бин_Пол', 'Год рождения']]     X.insert(0, 'константа', 1.0)    y = df['Вес'].apply(np.log)     xspitz = pd.Series([1.0, 183, 1, 1950])  # данные М.Шпитца    return np.exp( prediction_interval(X, y, xspitz) )
array([72.74964444, 97.46908087])

Этот пример возвращает диапазон между 72.7 и 97.4 кг., который как раз включает в себя вес Марка 73 кг., поэтому наше предсказание находится в пределах 95%-ого интервала предсказания. Правда оно лежит неудобно близко к границам диапазона.

Границы действия модели

Марк Шпитц родился в 1950 г., за несколько десятилетий до рождения самых возрастных пловцов на Олимпийских играх 2012 г. Пытаясь предсказать вес Марка, используя его год рождения, мы виноваты в том, что пытаемся экстраполировать слишком далеко за пределы наших тренировочных данных. Мы превысили границы действия нашей модели.

Есть и вторая причина, по которой этот результат сопряжен с проблемами. Наши данные полностью основаны на пловцах, которые соревнуются в наши дни на уровне международных стандартов, тогда как Марк не участвовал в соревнованиях уже много лет. Другими словами, Марк теперь не является частью популяции, на которой мы натренировали нашу модель. В целях исправления обеих этих проблем нам нужно поискать подробную информацию о Марке в 1979 г., когда он еще участвовал в соревнованиях по плаванию.

Согласно данным, в 1972 г. 22-летний Марк Шпитц имел рост 185 см. и весил 79 кг.

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

Следует отбирать признаки не только, опираясь на их предсказательную силу, но и на их актуальность для моделируемой области.

Окончательная модель

Хотя наша модель имеет чуть более низкий R2, давайте натренируем ее повторно, взяв в качестве признака возраст вместо года рождения. Это позволит нам легко предсказывать веса для прошлых и будущих ранее не встречавшихся данных, т.к. она ближе моделирует переменную, которая, как мы полагаем, имеет причинно-следственную связь с весом.

Модель произведет приблизительно с такими значениями:

Наши признаки для Марка на играх 1972 г. таковы:

Эти признаки можно использовать для предсказания его соревновательного веса при помощи приведенного ниже примера:

def ex_3_32():    '''Окончательная модель для предсказания        соревновательного веса'''    df = swimmer_data()    df['бин_Пол'] = df['Пол'].map({'М': 1, 'Ж': 0}).astype(int)     X = df[['Рост, см', 'бин_Пол', 'Возраст']]     X.insert(0, 'константа', 1.0)    y = df['Вес'].apply(np.log)     beta = linear_model(X, y)    # предсказать вес Марка Шпитца    xspitz = pd.Series([1.0, 185, 1, 22])     return np.exp( predict(beta, xspitz) )
78.46882772630318

Пример возвращает число 78.47, т.е. предсказывает вес 78.47 кг. Теперь результат находится очень близко к истинному соревновательному весу Марка, равному 79 кг.

Примеры исходного кода для этого поста находятся в моемрепона Github. Все исходные данные взяты врепозиторииавтора книги.

Резюме

В этой серии постов мы узнали о том, как определять наличие общей линейной связи между двумя и более переменными. Мы увидели, как выражать силу их корреляции при помощи корреляции Пирсона rи насколько хорошо линейная модель объясняет вариацию при помощи коэффициентов детерминации R2и R2. Мы также выполнили проверку статистических гипотез и рассчитали интервалы уверенности, чтобы вывести диапазон истинного популяционного параметра для корреляции.

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

Подробнее..

Бесплатная Школа наставников для разработчиков, тестировщиков и аналитиков стартует 5 июля

04.06.2021 12:23:32 | Автор: admin
Школа наставников это онлайн-интенсив из 5 занятий, где обучают будущих наставников сервиса онлайн-образования Яндекс.Практикум.

Наставники это опытные IT-специалисты, которые отвечают на вопросы студентов и проводят воркшопы по особенно сложным темам курса. Специалисты совмещают наставничество с основной работой, в зависимости от курса это занимает от 6 до 12 часов в неделю. Это оплачиваемая занятость.



Наставники это как преподаватели в университетах?


Нет. Это не та система онлайн-образования, где преподаватель разрабатывает программу, проверяет работы студентов и проводит вебинары. У нас наставники помогают студентам преодолевать сложности в обучении: общаются со студентами в Slack, объясняют сложные темы, проводят групповые вебинары и поддерживают мотивацию.

Кроме наставников у студентов в Практикуме есть целая команда сопровождения на протяжении обучения:

  • код-ревьюеры проверяют работы ребят и дают фидбэк в письменном виде;
  • кураторы модерируют чаты со студентами, составляют расписание, следят за дедлайнами;
  • менеджеры поддержки помогают с вопросами в онлайн-тренажере.

Подробно о том, чем занимаются наставники можно почитать в посте Наставничество в IT: растём сами и помогаем расти другим.

Или посмотрите доклад руководителя факультета backend-разработки Сони Техажевой Наставничество, или как вернуть огонь в свои отношения с программированием (с 4:15:00).


Зачем Практикуму нужны наставники со стороны? Почему нельзя обойтись силами специалистов Яндекса?


Часть наших наставников это, действительно, специалисты разных проектов Яндекса. Но мы не ограничиваемся этим и ищем специалистов из других компаний. Во-первых, наставничество это дополнительная занятость в нагрузку к основной работе, не каждый специалист из Яндекса к ней готов, а это значительно сужает количество потенциальных наставников. Во-вторых, мы хотим демонстрировать студентам широту взглядов в разработке, дизайне, аналитике и маркетинге, для этого у наставников должен быть разнообразный бэкграунд.

Какие требования есть к наставникам?


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

Все наставники проходят Школу наставников: мы обучаем их перед тем, как они начинают общаться со студентами, и снабжаем всеми материалами.

Как происходит отбор в Школу наставников?


При регистрации нужно заполнить небольшую анкету и приложить резюме. Если вы подходите по опыту, мы предложим сделать тестовое задание, следующий этап приглашение в Школу наставников.

Как выглядит и сколько времени занимает Школа наставников?


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

В Школе наставники отрабатывают типичные образовательные ситуации и получают обратную связь. Вы научитесь работать с потребностями студентов и их мотивацией.

Обучение состоит из групповых созвонов и индивидуальной практики. Вас ждёт пять воркшопов в вечернее время продолжительностью 2,5 часа и небольшие домашние задания, рассчитанные на 30-60 минут.

Всем, кто успешно пройдёт Школу, мы предлагаем работу наставником.

Подробности


Наставничество можно совмещать с основной работой, оно занимает от 6 до 12 часов в неделю. Вознаграждение от 35 до 50 тысяч рублей в зависимости от курса и потраченного времени.

Прямо сейчас мы ищем наставников на направления:

  • Java-разработчик
  • Go-разработчик
  • Python-разработчик
  • Мидл фронтенд-разработчик
  • Инженер по автоматизации тестирования
  • Аналитик данных
  • Специалист по Data Science
  • Дизайнер коммуникаций
  • Менеджер проектов в IT

Старт новой Школы наставников 5 июля 2021 года. До этого необходимо оставить заявку и выполнить тестовое задание.
Подробнее..

Что там в Университете ИТМО визуализация данных, цифровое искусство и научное кино

14.03.2021 18:20:23 | Автор: admin

Новая подборка мероприятий для студентов и специалистов. Здесь вы найдете ближайшие конференции, онлайн-трансляции, семинары и хакатоны, которые проведут при участии Университета ИТМО, организаций-партнеров, преподавателей и выпускников.

Фотография: Jonas Leupe. Источник: Unsplash.comФотография: Jonas Leupe. Источник: Unsplash.com

Техноэкскурсия Город, в котором ИТМО

22 марта пройдет в онлайн-формате

Университету ИТМО исполняется 121 год. В качестве одного из многочисленных тематических мероприятий мы планируем организовать онлайн-экскурсию по местам силы первого неклассического. Прогуляться по историческому центру Петербурга и познакомиться с ключевыми локациями Университета ИТМО помогут наши выпускники из WeGoTrip.

Ссылка на экскурсию появится в Vk-группе ITMO.Family. Пара других мероприятий сообщества пройдет 23-го и 25-го марта это будет open talk о спортивном развитии в университете будущего и онлайн-трансляция о еде будущего Foodtech с ИТМО из Международного научного центра SCAMT. В последнем случае ссылку на стрим тоже опубликуют в группе.


Хакатон Audithon 2021 от Счетной палаты

25-28 марта [подать заявку] пройдет в онлайн-формате

Счетная палата Российской Федерации и корпоративный акселератор GenerationS собираются предложить участникам онлайн-хакатона ряд задач по аналитике и визуализации данных. Заняться их решением можно в команде или самостоятельно организаторы приглашают подать заявку дата-сайентистов, журналистов, аналитиков, дизайнеров и программистов.

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



IV международная конференция English for Specific Purposes

8-9 апреля [зарегистрироваться] в онлайн-формате

Мероприятие пройдет под лозунгом more than ESP: from the classroom to the workplace. Организаторы вместе с участниками займутся теорией и практикой обучения студентов различных специальностей английскому для особых целей: обсудят тренды в этой области и новые методы преподавания. Подать заявку можно по следующим направлениям:

  • English for Specific Purposes;

  • English as a Medium of Instruction;

  • English for Academic Purposes;

  • Teacher Development;

  • Digital Learning.

Участвовать рекомендуют не только преподавателям, но и управленцам в сфере образования тем, кто интересуется edtech, работает в частном секторе или в государственных структурах.


Научное кино для наших студентов и сотрудников

19 марта 10 апреля Кронверкский пр., д.49 плюс онлайн-часть

Целых семнадцать пар от программного директора фестиваля актуального научного кино ФАНК и Центра научной коммуникации Университета ИТМО. Здесь будет теория и практика: от знакомства с историей кино с точки зрения научной коммуникации до разбора действующей индустрии жанров, направлений и примеров научного кино. Расскажем о наиболее примечательных кейсах, поможем разобраться с основами продакшена и дистрибуции. Помимо этого предложим поработать над собственным проектом научпоп-фильма в команде.

Программа и расписание курса есть тут. Контакты куратора для регистрации здесь.



Фестиваль цифрового искусства AR+T

27-28 апреля детали объявят ближе к мероприятию

Совместный эвент нашего факультета программной инженерии и компьютерной техники, АНО Центр современных технологий в искусстве Арт-паркИНГ и генерального партнера Санкт-Петербургского государственного музея театрального и музыкального искусства.

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


Что еще стоит знать их предстоящих событий:


Подробнее..

Прокторинг на стероидах, или как контролировать онлайн-экзамены

20.04.2021 10:21:38 | Автор: admin

Недавно ProctorEdu и КРОК запустили систему для контроля онлайн-тестирования на экономическом факультете МГУ. Она помогает наблюдать за студентами, которые сдают экзамен.

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

Такой подход к онлайн-обучению, прокторинг, первыми внедрили Coursera и Udemy. Разработчики ProctorEdu задумали собственную систему прокторинга в 2016 году именно для учебных заведений, но вскоре поняли, что она способна решать другие, более серьезные задачи.

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

Взять тестирование на знание основ информационной безопасности. Сотрудники уязвимое звено в защите любой компании, и было бы действительно здорово, если бы все они выучили базовые меры предосторожности. Возможно, тогда бы Uber не оштрафовали на $1.2 млн. за утечку персональных данных, и не произошло скандала со взломом Twitter.

А ведь есть ответственная и опасная работа, где от знания должностных инструкций и техники безопасности зависят жизни людей.

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

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

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

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

Как это работает

Во время экзамена ProctorEdu ведет запись с камеры, микрофона и экрана компьютера.

Система отслеживает, кто находится в кадре: сравнивает человека с фотографией, сделанной перед началом тестирования, или со сканом паспорта, загруженного перед экзаменом.

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

Обычно, когда алгоритм фиксирует нарушения, например, теряет человека из виду, система сначала выводит на экран предупреждение. Если участник не реагирует, ProctorEdu приостанавливает тестирование, до тех пор, пока он не исправится. При этом делается отметка о нарушении регламента, к которой можно вернуться позже при просмотре видеозаписи экзамена.

На основе нарушений по формуле рассчитывается рейтинг достоверности результатов экзамена.

E [0, 100] оценка доверия (если E < 0, то E = 0), xk усредненное за сеанс значение метрики k, wk весовой коэффициент метрики k, M {b1,b2,c1,c2,...} метрикиE [0, 100] оценка доверия (если E < 0, то E = 0), xk усредненное за сеанс значение метрики k, wk весовой коэффициент метрики k, M {b1,b2,c1,c2,...} метрики

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

Протокол сеанса в PDF-форматеПротокол сеанса в PDF-формате

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

В таком сценарии проктор может эффективно контролировать до 30 участников. Ему практически не нужно вмешиваться в ход экзамена. Система сообщает о нарушениях в реальном времени и подсказывает, на кого из подопечных обратить внимание.

Проктор может развернуть видео на весь экран и приглядеться к происходящему, объяснить участнику, что тот делает не так, предупредить о нарушении, приостановить или досрочно завершить экзамен.

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

Ограничения браузера и детекция лиц

Запись камеры и экрана, распознавание лиц, логирование клавиатуры Это звучит не секьюрно, поэтому разработчики ProctorEdu сознательно отказались от идеи устанавливать свое ПО на компьютеры участников экзамена.

ProctorEdu работает через браузер при помощи супервизор SDK JavaScript-библиотеки, в которой реализованы алгоритмы машинного обучения.

SDK не требует установки расширений и плагинов. ProctorEdu интегрируется с сервисом онлайн-тестирования при помощи стандарта IMS LTI или нескольких API-команд. Система запускается на странице тестирования и работает параллельно с ним.

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

Конечно, с таким подходом связаны определенные сложности. Разработчики сами наложили на себя ограничения, с которыми теперь вынуждены жить. Например, у системы нет доступа к оборудованию, процессам, окнам и другим ресурсам компьютера. Поэтому тестирование проходит в той же вкладке, где работает прокторинг. Это позволяет отслеживать переключение фокуса на другие вкладки и окна. Есть и нюансы, связанные с архитектурой и нейросетями.

Распознавание лиц в ProctorEdu реализовано при помощи сверточных нейросетей с использованием OpenCV и Dlib. Они регулярно переобучаются на свежесобранных данных. Для детекции лиц используется отдельная модель.

Разработчики с самого начала планировали запустить эти алгоритмы в браузере. Обычно такие задачи решают при помощи компиляции C++ в WebAssembly (Wasm). Считается, что это хорошая практика.

Чисто теоретически Wasm работает быстрее, чем JavaScript сценарий, но на практике выяснилось, что он медленнее, потребляет больше памяти и процессора, весит больше. Только загрузчик такого кода получается от 10 МБ.

Пришлось разрабатывать на JavaScript в несколько итераций. Первые версии были слабенькими и часто ошибались, но со временем команда ProctorEdu добилась стабильной работы и вывела это решение в продакшн.

Получилось быстро и компактно, но через какое-то время Сколтех пожаловался, что система не видит некоторых студентов. Оказалось, что курсы этого института проходит много чернокожих ребят, которые подключаются прямо из Африки, и алгоритм действительно не всегда их замечает.

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

Если за спиной студента окно, или он сидит на ярком солнце в белой с иголочки рубашке, камера выставляет экспозицию по самому светлому участку изображения. Черты лица затемняются, сливаются, и алгоритму не с чем работать. Пришлось добавить рекомендации по освещению в инструкцию для участников экзамена.

Сейчас разработчики планируют перенести в браузер и алгоритм распознавания лиц. Пока что модель великовата (2030 Мбайт с учетом сжатия), это в то время как все SDK весит около 1 мегабайта. Но здесь стоит постараться и найти решение.

Когда все изображения будут распознаваться в браузере, расходы на хостинг сократятся на добрых 30%. К тому же, на сервер будут передаваться только дескрипторы, по которым нельзя восстановить оригинальное изображение, а фото и документы так и останутся на компьютерах пользователей.

Серверная часть ProctorEdu

Кстати, об архитектуре системы.

Основной компонент ProctorEdu сервер приложений. Он работает на Node.js и занимается обработкой веб-запросов и веб-сокетных соединений. Сервер приложений связан с базой MongoDB. Там хранятся все данные, не являющиеся бинарными объектами. Для файлов, изображений, записей экзаменов предусмотрено отдельное S3-совместимое объектное хранилище.

Архитектура ProctorEdu включает отдельный сервис под API распознавания лиц и документов, и TURN-сервер для координации WebRTC-подключений между компьютерами участников.

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

Вся система поддерживает горизонтальное масштабирование. Ее компоненты упакованы в контейнеры. Их можно разбросать по разным физическим серверам и собрать кластерную конфигурацию в режиме мастер-мастер. Тогда нагрузка будет распределяться равномерно.

Обычно ProctorEdu разворачивают на базе одного из российских хостингов, поддерживающих хранение персональных данных, но систему можно запустить и на локальном сервере, как в проекте с МГУ и КРОК.

Требования к железу невысокие: компьютер с восьмиядерным процессором и 8 ГБ оперативной памяти потянет порядка 500 одновременных сессий. Однажды ProctorEdu обслуживала больше 5 тыс. одновременных участников экзамена и понадобилось всего 6 серверов для обработки клиентских запросов.

Можно ли обмануть систему?

Можно, но не так, как это обычно пытаются сделать.

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

Был случай, когда один из участников подготовился особенно серьезно: напечатал чужое фото на листе А4, вырезал глаза, привязал резинку и использовал как маску.

Конечно, это все легко детектируется.

Раньше можно было поставить смартфон перед монитором так, что его не было видно с фронтальной камеры. Казалось, что участник постоянно смотрит только на монитор. Теперь ProctorEdu обеспечивает и боковой обзор. К системе подключается вторая камера или тот же смартфон.

Еще можно попробовать списывать при помощи удаленного рабочего стола или виртуальной машины. Отследить их с вкладки браузера практически невозможно. Чтобы закрыть эту возможность, в систему добавили интеграцию с Safe Exam Browser.

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

Конечно, и это не панацея. Если постараться, Safe Exam Browser можно обмануть. Еще можно раздобыть скрытые наушники или аппаратный сплиттер для мониторов. Любой алгоритм можно обойти, вопрос лишь в том, сколько усилий для этого потребуется. ProctorEdu делает так, чтобы было проще выучить, чем смухлевать. И наши клиенты подтверждают, что система успешно справляется с этой задачей.

Подробнее..

Вебинар Стандарт С20 обзор новых возможностей C, введённых Стандартом C20

17.02.2021 14:23:34 | Автор: admin
25 февраля Яндекс.Практикум проводит открытый вебинар Стандарт С++20. Приглашаем разработчиков С++, которые хотят использовать последние возможности языка, а также программистов на других языках, которые хотят узнать, какие преимущества даёт разработка на C++.

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

Вебинар будет состоять из двух частей: 70 минут обзор новых возможностей, 20 минут ответы на вопросы.



В программе


  1. Краткая история Стандартов. Что привело к C++20.
  2. Модули как новая эпоха языка:
    Долгожданный документ принят панацея или ошибка?
    Как С++ преодолевает 30-летнее отставание.
    Как сломать систему сборки.
  3. Оператор космического корабля:
    Один за шестерых, но это ещё не всё.
    Порядки в C++ выходят на новый уровень.
  4. Концепты и констрейнты. Средство от криптографических ошибок на 10000 строк или нечто большее?
  5. Ranges. Просто адекватная замена парам итераторов или новый стиль в программировании?
  6. Корутины:
    Что это, и почему их время ещё не пришло.
    Как сломать отладчик.
  7. Приятные и важные мелочи. Краткий обзор других фич Стандарта:
    Designated initializers, инициализаторы в Ranged-for, span, календарь, format, шаблонные лямбды и другое.
    Что ещё дал нам C++20.
  8. Будущее. Чего ожидать от C++ дальше.

Ведущий


Вебинар проведёт Георгий Осипов автор факультета Разработчик C++ в Яндекс.Практикуме, разработчик в Лаборатории компьютерной графики и мультимедиа ВМК МГУ.

Вебинар пройдёт 25 февраля в 19.30 (Мск).
Бесплатная регистрация.
Подробнее..

Пройти до конца почему бросать и снова начинать учиться это нормально

22.05.2021 18:12:52 | Автор: admin

Многие из нас начинают и бросают много самых разных дел. В этом плане онлайн-обучение не исключение, а один из самых частых примеров. По данным исследования, проведённого в России в 2020 году, только у 28 % онлайн-школ до конца курса доходят 70 % учеников и более. В мире в целом доходимость два-три года назад ещё ниже: в среднем курс заканчивали только 3 % из тех, кто его начал, причём показатель с годами падал всё сильнее.

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


Проблема 1. Нет времени

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

Нет времени самая частая причина, по которой взрослые студенты всё реже заходят на курс и постепенно его забрасывают, рассказывает лид проведения Product Live SkillFactory Регина Сметанкина.

Людям очень сложно совмещать учёбу и работу, приходить вечером домой и заставлять себя заниматься. Чаще всего нет времени именно из-за основной работы, затем идёт учёба, затем студенты с детьми, мамы в декрете. Самое важное напоминать ученику о его первоначальных целях, зачем он пришёл, каким был его запрос. Мы собираем данные из его анкеты либо слушаем звонок в отдел продаж, когда он ещё при выборе курса рассказывает, зачем он пришёл.

По словам Регины, первоначальная причина это главное, о чём нужно вспомнить, когда пропадает желание учиться. Кто-то шёл освоить новую профессию, потому что старая надоела, мало денег или он достиг своего потолка. Кто-то идёт прокачать свои скиллы, чтобы получить повышение, поднять зарплату или наладить рабочие процессы. Важно помнить, что поначалу тяжело, но дальше будет легче.

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

Наши координаторы связываются со студентами, помогают наладить расписание. Мы говорим им, что, если выделять время только по выходным, это будет не так продуктивно, чем заниматься каждый день по 1,52 часа, но зато обучение будет стабильно продолжаться. У нас есть расписание курса, но если кто-то не успевает за ним (по разным причинам), мы готовы помочь решить сложности. Главное чтобы студенту было комфортно, продолжает Регина. Расписание курса можно рассматривать как путеводитель по тому, в каком порядке проходить модули. Если человек сильно отстал и не хочет идти один, мы можем также перевести его на другой поток, который начал обучение чуть позже.

В нашем блоге рассказали историю Виктора, который был продакт-менеджером, но решил уйти в Data Science (и это в 40 лет!) и сейчас работает на позиции Middle Data Scientist.

Проблема 2. Усталость/выгорание

Мария насмотрелась на друзей, окончивших онлайн-курсы и получивших работу в новой сфере, пошла сама, но растерялась из-за сложной подачи информации и бросила. Мария понимает, что ей интересна эта профессия, но чувствует, что нужна передышка.

Мария в этом случае проходит классический путь студента онлайн-курсов, так что такая ситуация абсолютно нормальна, говорит Регина Сметанкина.

Студент всегда может взять перерыв, например, по причине отпуска, семейных дел А еще существует заморозка курсов на нужный срок. Цель школы не просто доучить студента, а помочь ему достигнуть поставленной на обучение цели, поэтому мы всегда открыты к диалогу и обсуждению возникающих сложностей".

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

Когда студент не заходит на образовательную платформу 12 недели, за дело берутся координаторы. Сначала они связываются с ним в Slack, а если это не оказалось успешным, пишут в другие каналы или звонят и спрашивают, что случилось. Если студент признаётся, что пока не может учиться, мы делаем заморозку и по истечении её срока подключаем к актуальному потоку. Если надо освежить знания, предлагаем сбросить прогресс, чтобы заново прорешать задания. У нас есть студенты, которых мы переводили с потока на поток неоднократно (пожалуйста, учитесь!), и со временем они успешно заканчивают курсы, говорит Регина.

Не стоит опасаться потери прогресса у студента после заморозки снова появится доступ к заданиям и учебным материалам, как и право на сертификат о новой профессии, он сможет посмотреть вебинары онлайн либо в записи.

Проблема 3. Слишком сложно / завышенные ожидания

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

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

Когда ученик перестаёт заниматься и выясняется, что проблема именно в этом, координаторы доносят до него мысль, что здесь всё, как в школе. Со временем будет легче, главное войти в процесс и приучить себя заниматься, постепенно погрузиться в новую область.

Бывает, ученик говорит: Я переоценил себя, мои мозги не тянут, мне всё сложно, рассказывает Регина Сметанкина. На самом деле ученики очень часто на себя наговаривают. С опытом понимаешь, что иногда взрослые студенты ведут себя совсем как дети: они сталкиваются с одной проблемой и всё, они застопорились, я тупой, я ничего не понимаю. Начинаешь копать, а оказывается всё у него шло хорошо, он просто застрял на одной задаче. К таким студентам приходят на помощь координаторы и менторы. Я пришла к тому, что не нужно давить на то, чтобы обязательно прорешали всё по ходу курса. Студенты меня научили, что можно перейти к другому модулю или инструменту, потом вернуться и доделать.

Эта причина часто возникает ещё и тогда, когда студенты стесняются задавать вопросы менторам или преподавателям. Большинство наших студентов первый раз в жизни сталкиваются с программированием, у них появляются вопросы, но они боятся их задать, потому что кажется, будто остальные всё знают, а их вопрос покажется глупым, говорит методист курсов С#, QAP, QAJA Анна Мазалова. В итоге ученики начинают накапливать вопросы до момента, пока не накопится клубок нерешённых вопросов и они не поймут, что всё. Они уже не могут разобраться с этим и уже даже не знают, о чём спросить в первую очередь.

Как мы транслируем в школе: не нужно оставаться один на один с проблемой, продолжает Регина Сметанкина. Всегда готовы помочь наши менторы, это их работа. Часто помогают однокурсники. И уж точно не нужно бояться задавать вопросы. Студенты часто думают: Ой, у меня такой глупый вопрос, все умные, а мой вопрос дурацкий, я опозорюсь. Не бывает глупых вопросов. К тому же в Slack всегда можно посмотреть ответы на вопросы, которые уже задавали. И ещё: не нужно опускать руки, когда кажется, что не получается. Поделись проблемой с координатором он готов выслушать, дать совет.

Проблема 4. Разочарование в выборе

Светлана взялась за курсы, но в процессе поняла, что это вообще не её. Пыталась закончить из принципа, но разочаровалась окончательно и больше не хочет записываться ни на какие курсы, потому что опасается, что и с ними будет так же.

Частая проблема люди видят рекламу, где им говорят: пройдите курс и будете получать кучу денег, вот он я, разработчик, сижу с ноутбуком у моря, и у вас будет так же, рассказывает Анна Мазалова. У них создаётся впечатление, что они придут, им дадут волшебную таблетку, которая решит все проблемы, не нужно будет делать ничего самим. Но на деле оказывается, что нужно тратить время, выполнять задания, и у них происходит конфликт ожидание/реальность. Также мотивация теряется, когда люди понимают, что не могут получить очень быстрый результат. Потому что любой серьёзный курс со сменой профессии это полгода-год, а все хотят молниеносного результата. Нужно помнить, что первые 12 месяца это погружение, адаптация, изучение основ. Люди разбираются и в это время ещё не могут приступить к реальной практике, из-за чего теряется мотивация. Ещё один вариант: студент не разобрался в специфике профессии. Часто так приходят обучаться на тестировщика и только в процессе понимают, что это не их. Проблема недоинформированности.

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

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

Если с момента начала обучения прошло не больше двух недель, в SkillFactory сумму, уплаченную за курс, в полном объёме засчитывают в счёт оплаты новой специальности. Если студент решил уйти совсем, деньги ему вернут. Если прошло больше времени, оплату рассчитают по прогрессу студента на первом курсе и зачислят в качестве скидки при оплате нового. Если выбранный курс окажется дороже, часть средств ученику вернут, если дешевле, нужно будет доплатить разницу.

Проблема 5. Не нужно

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

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

Проблема 6. Кончились деньги

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

Как вернуться к обучению

Чаще всего сложности возникают на начальной стадии обучения, рассказывает PO of Student's Learning Experience Алексей Головенкин. Это примерно 12 месяца со дня старта курса.

Это вполне нормальная реакция человеческого организма мозг сопротивляется. Именно поэтому вновь прибывшим студентам мы стараемся уделять максимум внимания и фокусируемся на заботе о них. Если человек решил взять заморозку, то перед тем, как попрощаться, мы обязательно проговариваем дату следующей коммуникации. Такая дата служит договорённостью. В большинстве случаев студенты сами помнят о договорённостях, и возврат к обучению у них где-то зафиксирован.

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

Слишком завышенные требования к себе это одна из основных проблем, рассказывает старший методист направления Программирование Кристина Савченко. Студенты думают, что в первый день, неделю они должны сделать буквально всё, чуть ли не начать программировать. От того, что мы даём информацию постепенно, они иногда расстраиваются и теряют мотивацию, поэтому мы добавляем в модули информацию о том, что здесь важно притормозить. Учиться много и понимать всё сразу просто невозможно, исходя из особенностей строения нашего организма, поэтому надо относиться к себе более объективно, вспомнить, как мы учились в школе и университете.

По словам Кристины, ещё одна проблема в том, что ученики приходят с уверенностью, что программирование это легко. Минимум 3 месяца ты будешь учиться программировать, а то и полгода-год. Придётся гуглить, смотреть видео на YouTube, ведь нереально только получить информацию в модуле и пойти программировать. Да, там основа, но нужна и обратная связь от экспертов и авторов, советы менторов, важно посмотреть и почитать документацию для того, чтобы увидеть разницу мнений, сформировать свой навык. Только после этого всё уложится в голове, и человек будет понемногу становиться программистом.

Любой может столкнуться с проблемой: что-то полетит по работе, кто-то заболеет, говорит Регина Сметанкина. Нужно понимать, что это временно и вы всё нагоните. Много срывов происходит в первые месяцы учёбы, но случиться такое может и в середине, и даже ближе к концу. Наши студенты сами признаются, что им не хватает маленьких побед: юниты большие, прогресс есть, но такого, чтобы тебя по голове погладили, нет, и ты ощущаешь себя в отрыве. Вроде хороший показатель, но ты ещё не специалист и учишься. Такое бывает даже с самыми замотивированными студентами. Нужно помнить, что осталось чуть-чуть.

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

Резюмируем

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

  2. Если вам сегодня сложно, то, когда вы через месяц вернётесь к этому же материалу, окажется, что это очень просто. Вспомните, как вы учились складывать однозначные числа. Было сложно? Да! Но потом это стало просто. И вам уже не нужны пальцы, чтобы сложить 3 и 2. Здесь точно так же.

  3. Если вы не успеваете в дедлайны, не расстраивайтесь. У каждого свой ритм. Отдохните, сделайте перерыв на пару дней и вернитесь. Чтобы изучить новое, нужно время. Но не забывайте о своей цели, иначе отдых может затянуться.

  4. Не нужно стесняться спрашивать. Помните, что на курсе учатся такие же люди, как вы. И, если вам кажется, что ваш вопрос "глупый", это не так. Глупый только тот вопрос, который не задан. На курсе вы находитесь в безопасном пространстве, где можно спросить что угодно.Для тех кто учится самостоятельно это тоже актуально не смущайтесь спрашивать у более опытных.

  5. Помните, что обучение это работа. У вас есть материал, есть поддержка преподавателей, но 50 % вашего успеха в ваших руках! Внесите учёбу в расписание. Это поможет вам планировать своё время и не выгорать.

  6. Если что-то произошло, сообщите координатору курса, возможно, вместе вы сможете найти решение проблемы. Не оставайтесь с ней один на один.

Не важно как вы решите учиться на курсе или самостоятельно по книгам и туториалам, в любом случае не унывайте, помните о цели и старайтесь получать удовольствие от новых знаний. Цель мотивирует на прогресс в обучении. Обучение не всегда сначала даётся легко (вспомним школу), но если приложить немного усилий, то всё обязательно получится. Вспомните свои ощущения, когда вы только посеяли зёрнышко, чтобы стать специалистом в совершенно новой профессии. Согласитесь, это вдохновляет!

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

Другие профессии и курсы
Подробнее..

Как мы на хакатоне транспорт кластеризировали

30.03.2021 20:09:12 | Автор: admin

Привет, Хабр! Компьютерное зрение и искусственный интеллект одни из самых востребованных направлений в современном IT. Поэтому мы выбрали именно их для учебного"Межгалактического Хакатона 2021"который организовали НИТУ МИСиС и Zavtra.Online (подразделение SkillFactory по работе с университетами).

В хакатоне были представлены 5 кейсов от разных компаний, и одним из них был кейс от компании IntelliVision кластеризация изображений транспортных средств. Его и выбрала команда финалистов, описав реализацию подобного проекта от А до Я.


Начало работы

Целью любого кластерного анализа является поиск существующих структур. Так и в нашей задаче были даны изображения, которые нужно разбить на кластеры и интерпретировать каждый из них. В качестве исходных данных нам предоставили изображения транспортных средств разных типов, цветов, ракурсов и деталей. Исходные изображения были загружены в нейронную сеть, которая определила паттерны и построила модель, и эта модель отображается в виде вектора (дескриптора), полученного на промежуточном (скрытом) слое нейронной сети. Варианты дескрипторов, полученные с помощью глубокого обучения, были исходными данными для дальнейшей кластеризации: color_model, osnet, efficientnet-b7, type_model.

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

Дополнительным плюсом было то, что среди изображений могли быть выделены выбросы (изображения плохого качества, изображения, на которых нет транспортных средств, и т. д).

Особенности выполнения задания

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

Сначала проводилась работа по понижению размерности данных для увеличения скорости обучения моделей, но PCA давал малоинформативные результаты, а t-SNE из библиотеки scikit-learn имел низкую производительность. И тут на помощь пришёлRapids бесплатный open-source фреймворк для ускорения обработки данных от NVIDIA, в котором есть библиотека машинного обучения cuML. Задача была решена в Jupyter Notebook в Google Colab, так как в эту среду легко установитьRapids, а также использовать его совместно с GPU Tesla K80 с 13 Гб видеопамяти на борту.

Исследование набора данных color_model

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

Кандидатами в лучшее число кластеров на основе метода локтя оказались 3 и 4.

По визуализации результатов кластеризации (кандидаты в лучшие кластеры) для стандартизированных и нормированных данных видно, что предобработка данных повлияла на результат кластеризации. Разделение на 2 и 3 кластера почти одинаковое вне зависимости от способа обработки данных, но есть разница в разбиении на 4 кластера.

Это увеличенные результаты кластеризации на данных, размерность которых была понижена при помощи t-SNE. Видно, что алгоритм пытается выделять кластеры и один из них синий отделил успешно, но в целом чёткой границы нет.

По итогам экспериментов мы визуализировали случайные картинки для каждого из результатов разбиения на 2, 3, 4 кластера.

Видно, что в зависимости от потребностей при 2-х, 3-х и 4-х кластерах вне зависимости от типа обработки можно получить кластеры:

[Светлый-Тёмный],

[Светлый-Тёмный-Цветной],

[Светлый-Серый-Тёмный-Цветной]

А что же другие алгоритмы? Мы попробовали также DBSCAN, и у него получилось выделить отдельно выбросы фото низкого качества. Это фото с включёнными фарами, вблизи и сзади. Интересный эффект кластер жёлтых автомобилей.

Видно, что, комбинируя K-means и DBSCAN, можно в зависимости от потребностей получить разбивку на цветовые кластеры с различной детализацией, а также выделить выбросы.

Исследование набора данных osnet

Следующим набором дескрипторов, на котором мы провели исследования, сталosnet.

Из условий задачи нам было известно, что для построения дескрипторов osnet использовалась нейронная сеть, обученная для повторной идентификации людей, животных и машин (reID). В отличие от type_model и color_model эта модель не обучалась на исходном датасете veriwild.

В связи с этим мы предположили, что модель, обученная на наборе дескрипторов osnet, должна объединять в кластеры объекты не только по цвету и типу транспортных средств, но и по другим признакам (например, ракурсу съёмки).

В связи большим размером данныхosnet(csv файл из 416314 строк и 512 столбцов) и ограниченности имеющихся вычислительных мощностей и сроков все эксперименты проводились на предобработанных данных с пониженной при помощи t-SNE размерностью.

Помимо простого алгоритма k-Means мы решили проверить Mini-Banch k-Means. Как и ожидалось, Mini-Banch k-Means справился быстрее, но качество кластеризации, показанное простым k-Means, оказалось лучше.

Как и на других наборах данных, оптимальное число кластеров определяли с помощьюметода локтя.Оптимальными кандидатами являются 3-й и 4-й кластеры.

После стандартизации данных на диаграмме визуально определялось более чёткое разбиение на кластеры, но друг от друга кластеры не были изолированы.

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

В результате мы увидели, что при увеличении количества кластеров модель старается разделить выборку одновременно по цвету автомобиля и ракурсу съёмки.

Также мы увидели, что модель не разделила транспортные средства на отдельные кластеры в зависимости от типа: седан/джип/грузовик/автобус. Можно предположить, что другие параметры кластеризации позволят улучшить качество такого разбиения.

Особый интерес представляет способность модели выделять нестандартные кластеры. К примеру, нам показалось, что в одном из экспериментов модель выделила в отдельный кластер объекты с бликами и пятнами:

Исследование набора данных efficientnet-b7

Следующим этапом исследования было исследование работы модели на дескрипторе Efficientnet-b7. Этот дескриптор был самым большим по размеру (416314, 2560), данная модель классификации изображений обучена на Imagenet и до этой работы данных из veriwild не видела.

Было решено уменьшить размерность модели, чтобы была возможность в разумные сроки сделать кластеризацию на доступных компьютерах. Для этого применён метод t-SNE, как показавший ранее большую точность итоговых сжатых данных.

Далее модель быластандартизированаинормализована. Построенная после этого двухмерная визуализация, не разделённая на кластеры, выявила небольшие различия:

Затем кластеризовали данные на 2, 3, 4, 20 кластеров методом k-Means, как показавшим лучшие результаты на предыдущих моделях, описанных выше.

Аналогично описанию выше было определено исследуемое количество кластеров с помощью Elbow method clistering (метод локтя):

В силу схожей природы индекса Дэвиса Болдуина (ДБ) и метода локтя в данном исследовании взят индекс ДБ с его локтями в точках 9 и 20. Для того чтобы компенсировать недостаток данного индекса, заключающийся во влиянии масштаба данных на значение индекса, применена нормализация данных перед исследованием (craftappmobile.com).

Визуализация для нормализованной модели:

Результаты кластеризации (в виду большого числа картинок, все под спойлерами):

3 кластера
Кластер 0 светлые машины, задом.Кластер 0 светлые машины, задом.Кластер 1 тёмные машины.Кластер 1 тёмные машины.Кластер 2 светлые машины, передом.Кластер 2 светлые машины, передом.
4 кластера попытка разделить на светлые/тёмные зад/перед
Кластер 0 светлые машины, передом.Кластер 0 светлые машины, передом.Кластер 1 тёмные машины, передом.Кластер 1 тёмные машины, передом.Кластер 2 светлые машины, задом много выбросов.Кластер 2 светлые машины, задом много выбросов.Кластер 3 тёмные машины, задом много выбросов.Кластер 3 тёмные машины, задом много выбросов.
9 кластеров попытка разделить на светлые/тёмные зад/перед ракурс тип кузова по цвету
Кластер 0 светлые машины, передом, ракурс направо, внедорожник (вэн) много выбросов.Кластер 0 светлые машины, передом, ракурс направо, внедорожник (вэн) много выбросов.Кластер 1 тёмные машины, задом, ракурс влево много выбросов. Кластер 1 тёмные машины, задом, ракурс влево много выбросов. Кластер 2 светлые машины, задом, ракурс влево.Кластер 2 светлые машины, задом, ракурс влево.Кластер 3 светлые машины, задом, ракурс вправо, внедорожник (вэн) много выбросов.Кластер 3 светлые машины, задом, ракурс вправо, внедорожник (вэн) много выбросов.Кластер 4 синие машины, передом, ракурс вправо.Кластер 4 синие машины, передом, ракурс вправо.Кластер 5 белые машины, передом, ракурс вправо, внедорожник (вэн).Кластер 5 белые машины, передом, ракурс вправо, внедорожник (вэн).Кластер 6 белые машины, задом, ракурс вправо, седан много выбросов.Кластер 6 белые машины, задом, ракурс вправо, седан много выбросов.Кластер 7 белые машины, передом, ракурс вправо, седан много выбросов.Кластер 7 белые машины, передом, ракурс вправо, седан много выбросов.Кластер 8 тёмные машины, передом, ракурс вправо много выбросов.Кластер 8 тёмные машины, передом, ракурс вправо много выбросов.
20 кластеров разделение по цвету зад/перед ракурс тип кузова
Кластер 0 красный, передом, влево много выбросов из-за сливающегося цвета фар.Кластер 0 красный, передом, влево много выбросов из-за сливающегося цвета фар.Кластер 1 т.-серый, перед, вправо, кроссовер.Кластер 1 т.-серый, перед, вправо, кроссовер.Кластер 2 синий, зад, вправо много выбросов.Кластер 2 синий, зад, вправо много выбросов.Кластер 3 белый, перед, вправо нет ошибок, кузов определён неточно: хэтчбек/кроссовер.Кластер 3 белый, перед, вправо нет ошибок, кузов определён неточно: хэтчбек/кроссовер.Кластер 4 св.-серый, зад, вправо, седан.Кластер 4 св.-серый, зад, вправо, седан.Кластер 5 т.-серый/чёрный, перед, влево, кроссовер.Кластер 5 т.-серый/чёрный, перед, влево, кроссовер.Кластер 6 белый, зад, вправо, кроссовер.Кластер 6 белый, зад, вправо, кроссовер.Кластер 7 белые, перед, вправо, седан.Кластер 7 белые, перед, вправо, седан.Кластер 8 белый, зад, влево, кроссовер.Кластер 8 белый, зад, влево, кроссовер.Кластер 9 т.-серый, перед, вправо, седан.Кластер 9 т.-серый, перед, вправо, седан.Кластер 10 т.-серый, зад, вправо, седан.Кластер 10 т.-серый, зад, вправо, седан.Кластер 11 св.-серый, перед, влево, вэн. Кластер 11 св.-серый, перед, влево, вэн. Кластер 12 св.-серый, перед, вправо, вэн.Кластер 12 св.-серый, перед, вправо, вэн.Кластер 13 белый, перед, вправо, седан.Кластер 13 белый, перед, вправо, седан.Кластер 14 т.-серый/чёрный, перед, влево, седан смешан с кластером 5.Кластер 14 т.-серый/чёрный, перед, влево, седан смешан с кластером 5.Кластер 15 белый, перед, влево, седан.Кластер 15 белый, перед, влево, седан.Кластер 16 т.-серый, зад, влево, седан.Кластер 16 т.-серый, зад, влево, седан.Кластер 17 св.-серый, перед, вправо, кроссовер.Кластер 17 св.-серый, перед, вправо, кроссовер.Кластер 18 чёрный, перед, вправо, кроссовер много выбросов.Кластер 18 чёрный, перед, вправо, кроссовер много выбросов.Кластер 19 чёрный, перед, вправо, седан.Кластер 19 чёрный, перед, вправо, седан.

Выводы:

  1. Модель кластеризации с 20 кластерами, определёнными методом локтя с помощью индекса Дэвиса Болдуина показала себя лучше, чем модели с меньшим количеством кластеров, и в целом достаточно информативно.

  2. После кластеризации стало заметно, что стандартизированная модель кластеризует заметно с большим количеством ошибок, чем нормализованная.

  3. Ошибок в кластере не более 33 % (3 из 9), но чаще 22 % (2 из 9), при этом всего кластеров с ошибками 40 % (8 из 20).

  4. Следует отметить, что модель плохо различает данные (фотографии), когда фары и машина одного цвета: происходит больше ошибок.

  5. Для упрощения работы с моделью можно применять методы уменьшения размерности, в частности, t_SNE показал лучший результат уменьшив размерность с (416314, 2560) до (416314, 2), что позволило использовать значительно меньшие мощности вычисления и получить вполне интерпретируемый результат.

  6. Более подробного анализа выбросов в данном разделе не производилось.

Исследование набора данных type_model

Набор данных в виде csv файла, имеющего 416314 и 512 столбцов, был получен при помощи модели определения типа, и в целом работа с ним была аналогична работе с набором color.

Кандидатами в лучшее число кластеров на основе метода локтя оказался случай с 6 кластерами. При этом расчёты и визуализации также осуществлялись для большего и меньшего числа кластеров

Кластеризация проводилась как на стандартных, так и на нормированных данных.

Как и в случае с набором данных color, результаты кластеризации на данных, размерность которых была понижена при помощи t-SNE, целом не дают чёткого деления на кластеры.

По итогам экспериментов мы визуализировали случайные картинки для каждого из результатов разбиения на 37 кластеров.

В случае с 3 кластерами, несмотря на относительно чёткое разделение, значимой кластеризации добиться не удалось. Нормированные данные дают некоторое разделение по размеру автомобилей.

Кластер 0 седаны (небольшие авто),
Кластер 1 кроссоверы (джипы),
Кластер 2 микроавтобусы, автобусы (крупные авто).

В случае с 6 кластерами их условно можно идентифицировать следующим образом:

Кластер 0 седаны (вид спереди).
Кластер 1 джипы, хэтчбеки.
Кластер 2 мини-вэны.
Кластер 3 седаны (вид сзади).
Кластер 4 грузовики.
Кластер 5 хэтчбеки.

Ожидаемая кластеризация по типу кузова транспортного средства на основе подхода K-MEANS не была достаточно уверенной, однако подход для всех кластеров стабильно показывает кластеризацию по виду (спереди, сзади), например, седаны по виду спереди и сзади. Существует кластер для пикапов и мини-вэнов (кластеризация по размерам), хэтчбеки и джипы в остальных кластерах выделяются плохо. Автобусы появляются в 7 кластерах в группе с мини-вэнами с шумом от предыдущей кластеризации. Возможным решением является разделение отдельных кластеров на подкластеры.

Заключение

Несмотря на крайне сжатые сроки, поставленная задача была выполнена, и были получены интерпретируемые результаты, которые можно использовать в дальнейшей работе. У кого будут добавления смело делитесь ими в комментариях. Прилагаем ссылку на репозиторий вGitHub, а итоговый файл с разметкой кластеров расположен в репозитории и доступен поссылке.

Участники командыCloud_9:

  • Екатерина Лушпина Team Leader / презентация / коммуникация / статья;

  • Анастасия Сухоносенко Product Manager / план исследования / код-фреймворк / презентация / статья;

  • Александр Кудрявцев Speaker, Team Member / исследование / презентация / спикер / статья;

  • Наталья Авдеева Team Member / исследование / презентация / статья;

  • Павел Озернов Team Member / исследование / техническая поддержка / презентация / статья.

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

Примечание редактора

Если в вашей компании есть кейcы по Data Science, которые вы бы хотели решить в рамках хакатона или стать ментором пишите в личные сообщенияskillfactory_school. Также мы будем рады индустриальным партнёрам для наших программ и можем предложить им разные виды сотрудничества: членство в наблюдательном совете, экспертиза для создания курсов, стажировки в ваших компаниях для студентов и другие виды партнёрства. Давайте развивать Data Science вместе!

Узнать больше про нашу магистратуру можно на сайтеdata.misis.ruи вTelegram-канале.

Ну, и, конечно, не магистратурой единой!.. Хотите узнать больше проData Science,машинное и глубокое обучение заглядывайте к нам на соответствующие курсы; будет непросто, но увлекательно.

Узнайте, как прокачаться в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Английский язык выбери меня, птица счастья

26.05.2021 12:10:08 | Автор: admin

Как выбрать школу или преподавателя иностранного языка, чтобы не потерять время и деньги? Объясняем на пальцах.

Это такая же непростая задача, как выбрать подрядчика для выполнения любых работ и оказания любых услуг, в которых вы не профи.

Есть некоторые признаки, по которым можно понять, добросовестный перед вами исполнитель или не очень.

  1. Вам обязательно должны предложить входное тестирование, если вы не нулевик. Тестирование должно быть письменным и устным. Письменное - с возможностью выяснить у преподавателя, где сделаны ошибки. Какие это ошибки грубые или нет, скорее грамматические или скорее лексические. На устном тестировании следует обращать внимание на то, какие вопросы вам задают, открытые или закрытые. Закрытые вопросы это те, на которые вы отвечаете да или нет. Чтобы проверить вашу речь, вопросы должны быть открытые, то есть у вас должен быть шанс поговорить. Плохо, когда вас записывают в группу или берут на индивидуальные занятия, ориентируясь на тот уровень, который вы сами указали. (Исключение - свежий языковой сертификат, который есть у вас на руках). Редко кто оценивает свой уровень объективно - и это нормально.

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

  3. Подрядчик должен хорошо ориентироваться в современных учебниках* английского. Лучше, если таким хорошо ориентированным будет преподаватель, а не менеджер. Менеджер - это продажник, он может быть любым, учить вас будет не он. Задайте вопрос преподавателю, пусть он назовет хотя бы несколько учебников, по которым он работал или работает. Есть издательства, за ними стоят научные институты, которые разрабатывают учебные программы, к которым пишутся учебники. В штате научных институтов работают лингвисты, нейрофизиологи, нейролингвисты, методисты, теоретики и практики, это очень много спецов. Люди тратят годы, чтобы написать учебник. У каждого учебника есть концепция, а любой учебный комплекс включает в себя мануал для учителя. У разных учебников разные концепции. Об этом хороший преподаватель должен знать, даже если он работает по авторской методике. Скажем так, тем более, если он работает по авторской.

  4. Способов учить иностранный язык, если честно, всего два, - с переводом или без. Все остальное - это просто вариации на тему. Оба способа рабочие. Переводная методика - одна, там вариаций обычно не бывает, потому что она старая, все по ней учились в школе, продавать там особо нечего. Самая популярная методика без перевода - коммуникативная. Она же - коммуникативный метод, метод погружения, лексический подход, беспереводной метод и все, что на нее похоже, но таковой не является. Основной пул современных учебников написан именно под коммуникативную методику. Как понять, знает ли преподаватель, что такое коммуникативная методика? Спросить про учебники*. Спросить про методические пособия для преподавателей**. Спросить, что такое коммуникативная методика***. Спросить, чем дедуктивный метод отличается от индуктивного****. В случае последнего пункта термины можно и не знать, но объяснить принцип освоения учебного материала препод должен уметь.

  5. Подрядчик должен мочь продемонстрировать себя в деле. ( Жаль, что с ремонтниками так нельзя.) Если нельзя попробовать бесплатно, лучше заплатить один раз, чтобы понять, что все в порядке. Сходите на открытый урок или пробное занятие. Иногда ОУ - это презентация школы. Не тратьте время на то, что есть на сайте. ОУ должен показывать работу. Преподаватель не должен много говорить и говорить за вас. Умение задавать правильные вопросы и держать паузу один из признаков хорошего учителя. Если препод заставляет вас напрягаться и связывать слова в предложения, это хорошо, даже если вам трудно. Нехорошо, когда вам разрешают отделаться разрозненными словами, брошенными в пространство. Пример: Учитель: Как вы думаете, что такое любовь? Страсть! Доверие! Верность! Ср.: Я считаю, что любовь это когда люди доверяют друг другу и хранят верность, а страсть может и пройти. Отчасти это и ответ на вопрос Когда мы будем заниматься грамматикой на уроке? Вы занимаетесь грамматикой тогда, когда правильно формулируете, например, придаточное предложение. Урок должен иметь четкую структуру, которую вы без труда можете восстановить в памяти. Это признак того, что учитель готовился к уроку. Не должно быть ощущения хаоса, учитель не должен быть похож на ребенка, мечущегося по супермаркету и хватающего с полок все подряд: И вот это еще возьму, и вот этого немного, а вот еще штучка красивая. В общем, спросите у преподавателя, пишет ли он планы к своим занятиям. Он должен, даже если у него есть учебник и мануал к нему.

Что не имеет значения? Неважно, насколько дигитализировано учебное пространство, есть ли в нем приложения, платформы и личные кабинеты. За последние несколько тысяч лет человеческий мозг не эволюционировал и не превратился в компьютер с портом для перекачки информации, а люди по-прежнему читают и пишут тексты, слышат и воспроизводят речь. Да, технический прогресс рванул, а мозг - нет. И вся ирония жизни в том, что мозгу для того, чтобы учиться, должно быть сложно.

* Например: English File, Outcomes, Upstream, Empower, Серия In use

** Можно услышать названия (например, Lexical grammar или The book of pronunciation), а лучше имена (скажем, Скривенер, Андерхилл, Кристал, Селиван; первый - это главный у преподов английского, его нельзя не знать)

*** См.пункт 5, там есть пример. А если по-простому, то коммуникативная методика учит людей пользоваться речью для решения коммуникативных задач, - от самых простых (спросить дорогу, услышать объявление на вокзале, прочитать записку, написать ответный мейл) до сложных (выступить на конференции, посмотреть новый фильм на английском, прочитать книгу, написать статью на английскую версию хабра). Пусть тот, кого вы спрашиваете, приведет вам свой пример.

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

Бонус-трек. Если после тестирования вам покажется, что вы лучше, сильнее и быстрее того уровня владения языком, который вам определил преподаватель, то хороший препод будет с вами спорить. Скорее всего потому, что при определении уровня владения языком он руководствуется CEFR ( уровни владения иностранными языками, прописанными Советом Европы). Спросите у преподавателя, что это за уровни. Знающий препод сможет вам показать, в чем вы не правы, на то он и профи. У нормальных профессионалов всегда есть ответы, а если их нет сразу, то профи никогда не постесняется сказать, что ему нужно время подумать и поискать ответ.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2023, personeltest.ru