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

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'

Скачать все из CloudApp

Некогда прекрасный сервис CloudApp в очередной раз решил монетизироваться и прислал письмо с сообщением о том, что со 2 апреля месячный лимит на загрузку составляет всего 10 файлов.

Your CloudApp account is changing on April 2. Most importantly, all free accounts will have a drop limit of 10 drops per month.

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

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import time
import json
import urllib
import urllib2
from dateutil.parser import parse

USERNAME = "mail@gmail.com"
PASSWORD = "superpass"


def request(url):
    # Digest Authentication
    authhandler = urllib2.HTTPDigestAuthHandler()
    authhandler.add_password('Application', url, USERNAME, PASSWORD)
    opener = urllib2.build_opener(authhandler)
    opener.addheaders = [('Accept', 'application/json')]
    urllib2.install_opener(opener)

    response = urllib2.urlopen(url)
    if response.getcode() == 200:
        body = json.loads(response.read())
        if len(body):
            return body

    return False


def download(url, created_at):
    if not url:
        return False

    try:
        print 'Source: %s' % url
        filename = url.split('/')[-1]
        filename = urllib.unquote(filename.encode('utf-8')).decode('utf-8')

        # if a file exists add created_at
        if os.path.isfile(filename):
            filename = '%s-%s' % (created_at, filename)

        print 'Downloading... %s' % filename
        urllib.urlretrieve(url, filename)
        os.utime(filename, (created_at, created_at))
    except IOError:
        download(url)
    except LookupError:
        pass


if __name__ == "__main__":
    page = 0
    result = True
    while result:
        page = page + 1
        result = request('http://my.cl.ly/items?per_page=100&page=' + str(page))

        if not result:
            break

        for n in result:
            source_url = n.get(u'source_url')
            created_at = int(time.mktime(parse(n.get(u'updated_at')).timetuple()))
            # print json.dumps(n, sort_keys=True, indent=4)
            download(source_url, created_at)

Как я готовлю Sublime Text 2 на OSX

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

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

Dev Build

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

OS X Command Line

Не один редактор не может быть полноценным без cli. Для использования Sublime Text 2 из консоли на официальном сайте есть небольшая инструкция. У меня стоит Homebrew и поэтому не надо создавать лишнюю папку, а достаточно изменить симлинк путь ~/bin/subl на /usr/local/bin/subl полностью команда:

ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" /usr/local/bin/subl

Теперь можно наслаждаться всеми прелестями cli, посмотреть список поддерживаемых команд можно набрав subl --help.

Replacement Icon

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

https://github.com/dmatarazzo/Sublime-Text-2-Icon

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

#!/bin/bash

# The direction this script is running in
THIS_DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cp "$THIS_DIR/Sublime Text 2.icns" "/Applications/Sublime Text 2.app/Contents/Resources/"
cp $THIS_DIR/Document\ Icons/*.icns "/Applications/Sublime Text 2.app/Contents/Resources/"

# Trickery to force icon replace
sudo find /private/var/folders/ -name com.apple.dock.iconcache -exec rm {} \; 2>/dev/null
killall -KILL Finder
killall -KILL Dock

Soda Theme

В дополнение к предыдущему пункту, я бы порекомендовал использовать альтернативную тему оформления окна - Soda Theme, она поставляется как в светлом так и в темном варианте. Все инструкции по установке можно найти в репозитории на Github.

https://github.com/buymeasoda/soda-theme

Plugins

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

Для установки большинства плагинов можно воспользоваться прекрасным плагином Sublime Package Control. Который позволяет автоматически устанавливать плагины и поддерживать их в актуальном состоянии.

Кроме того на Github можно обратить внимание на организацию Sublime Text Packages включающую в себя обширны список репозиториев с плагинами и сниппетами.

Spell check

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

  1. Скачиваем словарь для русского языка c сайта OpenOffice
  2. Меняем расширение с .oxt на .zip и распаковываем полученный архив. Нас интересуют только 2 файла, для русского словаря это ru_RU.dic и ru_RU.aff
  3. В меню Sublime Text нажимаем Preferences → Browse Packages, создаем там папку Language - Russian и копируем файлы словарей в нее.
  4. Теперь словари необходимо сконвертировать в UTF-8. Открываем файл c расширением .aff и смотрим на первую строку, там будет что-то вроде SET KOI8-R. Значит словарь в кодировке KOI8-R, конвертируем любым удобным способом, я воспользовался утилитой iconv. После конвертирования необходимо открыть файл ru_RU.aff и заменить строку с кодировкой на SET UTF-8.
  5. Готовую UTF-8 версию русского словаря можно скачать по ссылке и просто установить.
  6. После всех этих манипуляций проверка русской орфографии появится соответствующим пунктов в меню View → Dictonary → Language - Russian.

Preferences.sublime-settings

Не секрет что Sublime Text 2 имеет много предустановленных настроек которые можно посмотреть в меню Preferences → Settings - Default, редактировать данный файл не рекомендуется в связи с тем что он будет перезаписан при следующем обновлении. Все свои настройки необходимо вынести в отдельный файл, Preferences → Settings - User. Напоследок я решил выложить свои настройки которые установлены у меня в этом файле.

{
    "tab_size": 4,
    "translate_tabs_to_spaces": true,
    "detect_indentation": false,
    "trim_trailing_white_space_on_save": true,
    "highlight_line": true,
    "ensure_newline_at_eof_on_save": true,
    "fallback_encoding": "Cyrillic (Windows 1251)",
    "highlight_modified_tabs": true,
    "open_files_in_new_window": false,
    "theme": "Soda Dark.sublime-theme"
}

Обратно из облаков

Казалось бы все вокруг стараются перевести свои блоги подальше в облачные блогохостинги и не следить за тем как все работает. У меня же ситуация прямо противоположная, я наконец-то отказался от Tumblr‘а как от блоговой платформы и успешно мигрировал на standalone блог который написал на Django.

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

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

Пара слов о мелочах

  • Foundation 2.0 - дизайн я рисовать совсем не хотел и выбрал именно этот фреймворк как альтернатива twitter bootstrap‘у.
  • Markdown - переписал все посты в этот формат. Считаю его наиболее идеологически простым и удобным для пост процессинга в html.
  • Disqus 2012 - вышел и беты и теперь можно полнофункционально его использовать. Надеюсь в дискасе починят миграцию комментариев и я смогу перенести все старые комменты на новые адреса.