dotzero

↑ ↑ ↓ ↓ ← → ← → B A Start

Среднеквадратическое отклонение

Расскажу о среднеквадратическом отклонении на примере собак. Имея группу собак рост которых 600, 470, 170, 430 и 300 мм. Как узнать какие из этих собак большие, какие маленькие, а какие можно отнести к средним? Тут на помощь приходит среднеквадратическое отклонениеσ (греческая буква сигма).

Формула очень проста: это квадратный корень из дисперсии случайной величины. Что такое дисперсия? Это среднее арифметическое квадратов разностей от среднего арифметического.

А теперь конкретно на примере наших собак, все вычисления буду писать на python без использования numpy. Первым делом находим среднее арифметическое всех элементов:

dogs = [600, 470, 170, 430, 300]
average = sum(dogs) / len(dogs)
# 394

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

variance = sum([(n-average)**2 for n in dogs]) / len(dogs)
# 21704

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

standard_deviation = variance ** 0.5
# ~147

Таким образом имея среднеквадратическое отклонение (147) и среднее арифметическое (394) можно сказать, что верхний порог для средней собаки — 394 + 147 = 541, а значит собака ростом 600 мм — большая. Для маленьких собак этот порог — 394 - 147 = 247, а значит собака ростом 170 мм - маленькая.

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

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

variance = sum([(n-average)**2 for n in dogs]) / (len(dogs) - 1)
# 27130
standard_deviation = variance ** 0.5
# ~164

Lindau

Особенности работы Docker контейнеров MySQL и Nginx на OSX

В ожидании релиза Docker for mac приходится использовать Docker Machine и решать проблемы которые он создает при работе с Data Volumes. О решении проблем в MySQL и Nginx я бы и хотел рассказать.

Официальный контейнер MySQL работает как и ожидаешь, пока в файле docker-compose.yml не добавлено хранение /var/lib/mysql на Data Volume:

mysql:
  image: mysql:5.7
  volumes:
    - ./data/mysql:/var/lib/mysql

После таких манипуляций демон MySQL откажется загружаться будет сыпать проклятиями:

InnoDB: Operating system error number 13 in a file operation.
InnoDB: The error means mysqld does not have the access rights to
InnoDB: the directory.

Для исправления этого необходимо создать небольшой скрипт, который возьмет UID и GID директории /var/lib/mysql и присвоит их пользователю и группе mysql. Пример такого скрипта mysql-entrypoint.sh:

#!/bin/bash
set -e
echo '* Working around permission errors locally by making sure that "mysql" uses the same uid and gid as the host volume'
TARGET_UID=$(stat -c "%u" /var/lib/mysql)
echo '-- Setting mysql user to use uid '$TARGET_UID
usermod -o -u $TARGET_UID mysql || true
TARGET_GID=$(stat -c "%g" /var/lib/mysql)
echo '-- Setting mysql group to use gid '$TARGET_GID
groupmod -o -g $TARGET_GID mysql || true
echo
echo '* Starting MySQL'
chown -R mysql:root /var/run/mysqld/
/entrypoint.sh mysqld --user=mysql --console

Далее монтируем этот скрипт внутрь контейнера и заменяем им оригинальный entrypoint MySQL:

mysql:
  image: mysql:5.7
  command: "/mysql-entrypoint.sh"
  volumes:
    - ./data/mysql-entrypoint.sh:/mysql-entrypoint.sh
    - ./data/mysql:/var/lib/mysql

На этом проблемы с MySQL закончились и время поговорить о контейнере Nginx. При работе со статикой из Data Volume он жеcтко кеширует файлы и реал тайм редактирование css или js превращается в пытку.

http {
  ...
  sendfile off;
  tcp_nopush off;
  tcp_nodelay off;
  ...
}

Если такое произошло, то в nginx.conf можно добавить эти три параметра в секцию http, после чего сделать рестарт контейнера и проблема решена.

HTTP запросы для Python 2 и Python 3

Для Python существует замечательная библиотека для работы со всеми типами HTTP запросов - Requests, но когда нужно сделать что-то без внешних зависимостей, то встает вопрос велосипедостроения. Проблема еще более усиливается когда необходима одновременная поддержка Python 2 и Python 3.

Стандартная библиотека urllib.urlopen не поддерживает методы для отправки PUT и DELETE запросов, а кроме того в Python 3 перенесли большинство методов из urllib2 в urllib.request, что добавляет некоторые костыли в код, для совместимости с Python 2. Таким образом составил себе список того что мне необходимо:

  • Совместимость Python 2 и 3;
  • Отправка GET, POST, PUT, DELETE запросов;
  • Парсинг JSON ответа.

Посидев пару часов собрал свой велосипед совмещающий в себе все эти требования:

import sys
import json

try:
    # python3
    from urllib.request import build_opener, Request, HTTPHandler
    from urllib.error import HTTPError
    from urllib.parse import urlencode
except ImportError:  # pragma: no cover
    # python2
    from urllib2 import build_opener, Request, HTTPHandler, HTTPError
    from urllib import urlencode


def request(url, method='GET', data=None, headers={}):
    if data is not None:
        data = urlencode(data)
        if method in ['GET', 'DELETE']:
            url = url + '?' + data
            data = None
        else:
            x_www = 'application/x-www-form-urlencoded; charset=utf-8'
            headers.update({'Content-Type': x_www})
            if sys.version_info > (3,):  # python3
                data = data.encode('utf-8')

    try:
        opener = build_opener(HTTPHandler)
        req = Request(url, data=data, headers=headers)
        req.get_method = lambda: method
        response = opener.open(req).read()
        data = json.loads(response.decode('utf-8'))
    except HTTPError as e:
        data = json.loads(e.read().decode('utf-8'))
    except ValueError:
        return False

    return data

Можно легко проверить работу всех этих методов используя сервис httpbin.org

data = {'foo': 'bar'}
headers = {'x-header': 'x-value'}

resp = request('https://httpbin.org/get', data=data, headers=headers)
assert resp['headers']['X-Header'] == 'x-value'
assert resp['url'] == 'https://httpbin.org/get?foo=bar'
assert resp['args']['foo'] == 'bar'

resp = request('https://httpbin.org/post', 'POST', data=data, headers=headers)
assert resp['headers']['X-Header'] == 'x-value'
assert resp['url'] == 'https://httpbin.org/post'
assert resp['form']['foo'] == 'bar'

resp = request('https://httpbin.org/put', 'PUT', data=data, headers=headers)
assert resp['headers']['X-Header'] == 'x-value'
assert resp['url'] == 'https://httpbin.org/put'
assert resp['form']['foo'] == 'bar'

resp = request('https://httpbin.org/delete', 'DELETE', data=data, headers=headers)
assert resp['headers']['X-Header'] == 'x-value'
assert resp['url'] == 'https://httpbin.org/delete?foo=bar'
assert resp['args']['foo'] == 'bar'

Альбом с улиц Los Angeles

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

Мы решили поддержать его и купили тот альбом. Теперь же спустя полтора года я так и не смог найти о нем ничего нового кроме аккаунта в Instagram и решил выложить тот альбом на SoundCloud, чтобы послушать мог каждый.