Записки программиста, обо всем и ни о чем. Но, наверное, больше профессионального.

2015-11-03

Week 4, Lab 4

Курс Scalable Machine Learning. Hadoop, Apache Spark, Python, ML -- вот это всё.

Продолжаю конспектировать пройденный курс. Неделя 4.
В прошлый раз было про One-hot-encoding для трансформации фич в числа и про хеширование как средство снижения размерности датасета.
Пришло время потрогать пройденные темы на практике. Лабораторка.

CTR PREDICTION PIPELINE LAB PREVIEW

In this segment, we'll provide an overview
of the click-through rate prediction pipeline
that you'll be working on in this week's Spark coding lab.
The goal of the lab is to implement a click-through rate
prediction pipeline using various techniques that we've
discussed in this week's lecture


The raw data consists of a subset of a data
from a Kaggle competition sponsored by Criteo.
This data includes 39 features describing users, ads,
and publishers.
Many of these features contain a large number of categories

You'll next need to extract features
to feed into a supervised learning model.
And feature extraction is the main focus of this lab.
You'll create OHE features, as well as hashed features,
and store these features using a sparse representation.

Экстрагировать фичи это не так страшно как кажется. Банальная трансформация. Типа текстовых данных в числа; комбинированные фичи, и т. д.

Given a set of features, either OHE or hashed features,
you will use MLlib to train logistic regression models.
You will then perform Hyperparameter
tuning to search for a good regularization parameter,
evaluating the results via log loss,
and visualizing the results of your grid search.

Понятно вроде.
ОК, забираем нотебук

Запускаем виртуалку
valik@snafu:~$  pushd ~/sparkvagrant/
valik@snafu:~/sparkvagrant$  vagrant up
И вперед: http://localhost:8001/tree

На Гитхабе этот нотебук

Программа действий:
  • Part 1: Featurize categorical data using one-hot-encoding (OHE)
  • Part 2: Construct an OHE dictionary
  • Part 3: Parse CTR data and generate OHE features: Visualization 1: Feature frequency
  • Part 4: CTR prediction and logloss evaluation: Visualization 2: ROC curve
  • Part 5: Reduce feature dimension via feature hashing: Visualization 3: Hyperparameter heat map
Для справки

Part 1: Featurize categorical data using one-hot-encoding (OHE)

(1a) One-hot-encoding

Сначала создадим словарь OHE вручную, для разминки возьмем датасет из трех записей про трех животных.
# Data for manual OHE
# Note: the first data point does not include any value for the optional third feature
sampleOne = [(0, 'mouse'), (1, 'black')]
sampleTwo = [(0, 'cat'), (1, 'tabby'), (2, 'mouse')]
sampleThree =  [(0, 'bear'), (1, 'black'), (2, 'salmon')]
sampleDataRDD = sc.parallelize([sampleOne, sampleTwo, sampleThree])

sampleOHEDictManual = {}
sampleOHEDictManual[(0,'bear')] = 0
sampleOHEDictManual[(0,'cat')] = 1
sampleOHEDictManual[(0,'mouse')] = 2
sampleOHEDictManual[(1,'black')] = 3
sampleOHEDictManual[(1,'tabby')] = 4
sampleOHEDictManual[(2,'mouse')] = 5
sampleOHEDictManual[(2,'salmon')] = 6
Всего семь категорий.

(1b) Sparse vectors

Надо потренироваться в создании sparse векторов. Пока вручную.
import numpy as np
from pyspark.mllib.linalg import SparseVector
# TODO: Replace <FILL IN> with appropriate code
aDense = np.array([0., 3., 0., 4.])
aSparse = SparseVector(len(aDense), enumerate(aDense))

bDense = np.array([0., 0., 0., 1.])
bSparse = SparseVector(len(bDense), enumerate(bDense))

w = np.array([0.4, 3.1, -1.4, -.5])
print aDense.dot(w)
print aSparse.dot(w)
print bDense.dot(w)
print bSparse.dot(w)
Что характерно, несмотря на то, что такое решение удовлетворяет условиям теста (умножение дает одинаковые результаты), решение неправильное.
Правильно будет так:
aDense = np.array([0., 3., 0., 4.])
aSparse = SparseVector(len(aDense), {1: 3., 3: 4.})
bDense = np.array([0., 0., 0., 1.])
bSparse = SparseVector(len(bDense), [(3, 1.)])

Почему? Потому, что гладиолус. Смотри определение SparseVector.

(1c) OHE features as sparse vectors

Теперь, когда идея понятна, создадим SparseVector-ы для игрушечного датасета с животными.
Если идея непонятна, то вот: имеем семь категорий, значит вектор будет длинной 7. Изначально весь в нулях. Для каждой записи берем такой вектор и ставим единички по номерам из словаря, ключ в словаре – исходная фича записи.
Пример: (животное, мышка) в словаре дает 2. Значит в SparseVector ставим единичку в позиции 2 (считая с 0).

# sampleOHEDictManual[(0,'bear')] = 0
# sampleOHEDictManual[(0,'cat')] = 1
# sampleOHEDictManual[(0,'mouse')] = 2
# sampleOHEDictManual[(1,'black')] = 3
# sampleOHEDictManual[(1,'tabby')] = 4
# sampleOHEDictManual[(2,'mouse')] = 5
# sampleOHEDictManual[(2,'salmon')] = 6

# sampleOne = [(0, 'mouse'), (1, 'black')] = 2, 3
sampleOneOHEFeatManual = SparseVector(7, {2: 1.0, 3: 1.0})
# sampleTwo = [(0, 'cat'), (1, 'tabby'), (2, 'mouse')] = 1, 4, 5
sampleTwoOHEFeatManual = SparseVector(7, {1: 1.0, 4: 1.0, 5: 1.0})
# sampleThree =  [(0, 'bear'), (1, 'black'), (2, 'salmon')] = 0, 3, 6
sampleThreeOHEFeatManual = SparseVector(7, {0: 1.0, 3: 1.0, 6: 1.0})

Несложно, правда? А я довольно долго колупался, пока не сообразил, как надо правильно записывать SparseVector-ы.

(1d) Define a OHE function

Напишем функцию, которая возвращает нам SparseVector для записи исходного датасета.

def oneHotEncoding(rawFeats, OHEDict, numOHEFeats):
    """Produce a one-hot-encoding from a list of features and an OHE dictionary.

    Note:
        You should ensure that the indices used to create a SparseVector are sorted.

    Args:
        rawFeats (list of (int, str)): The features corresponding to a single observation.  Each
            feature consists of a tuple of featureID and the feature's value.
            (e.g. sampleOne) sampleOne = [(0, 'mouse'), (1, 'black')]
        OHEDict (dict): A mapping of (featureID, value) to unique integer.
            OHE Dictionary example:
                sampleOHEDictManual[(0,'bear')] = 0
                ...
                sampleOHEDictManual[(1,'black')] = 3
                ...
                sampleOHEDictManual[(2,'salmon')] = 6
        numOHEFeats (int): The total number of unique OHE features (combinations of featureID and
            value).

    Returns:
        SparseVector: A SparseVector of length numOHEFeats with indicies equal to the unique
            identifiers for the (featureID, value) combinations that occur in the observation and
            with values equal to 1.0.
            e.g. sampleOneOHEFeatManual = SparseVector(7, {2: 1.0, 3: 1.0})
    """
    spDict = {}
    для каждой фичи:
        key = значение из словаря ОХЕ
        if key is not None:
            spDict[key] = 1.0
    res = SparseVector(numOHEFeats, spDict)
    return res

# Calculate the number of features in sampleOHEDictManual
numSampleOHEFeats = len(sampleOHEDictManual)

# Run oneHotEnoding on sampleOne
sampleOneOHEFeat = oneHotEncoding(sampleOne, sampleOHEDictManual, numSampleOHEFeats)

(1e) Apply OHE to a dataset

Ну, тут все элементарно, применить функцию к исходному датасету, получив закодированный датасет, готовый к скармливанию в logistic regression.
sampleOHEData = sampleDataRDD.map(lambda x: oneHotEncoding(x, sampleOHEDictManual, numSampleOHEFeats))
print sampleOHEData.collect()
[SparseVector(7, {2: 1.0, 3: 1.0}), SparseVector(7, {1: 1.0, 4: 1.0, 5: 1.0}), SparseVector(7, {0: 1.0, 3: 1.0, 6: 1.0})]

Part 2: Construct an OHE dictionary

(2a) Pair RDD of (featureID, category)

Надо автоматизировать создание словаря. А то он у нас был ручками записан.
Для начала создадим RDD с уникальными значениями фич из исходного списка списков.
create an RDD of distinct (featureID, category) tuples

# sampleOne = [(0, 'mouse'), (1, 'black')]
# sampleTwo = [(0, 'cat'), (1, 'tabby'), (2, 'mouse')]
# sampleThree =  [(0, 'bear'), (1, 'black'), (2, 'salmon')]
# sampleDataRDD = sc.parallelize([sampleOne, sampleTwo, sampleThree])
sampleDistinctFeats = (sampleDataRDD
                       .плоский список(lambda x: x)
                       .выкинуть дубли())

(2b) OHE Dictionary from distinct features

Вот теперь можно сгенерировать словарь, сопоставив уникальные категории номерам по порядку.
sampleOHEDict = (sampleDistinctFeats
    .сгенерить индексы()
    .собрать словарь())
print sampleOHEDict
{(2, 'mouse'): 0, (0, 'cat'): 1, (0, 'bear'): 2, (2, 'salmon'): 3, (1, 'tabby'): 4, (1, 'black'): 5, (0, 'mouse'): 6}

(2c) Automated creation of an OHE dictionary

Собираем лего: напишем функцию, которая вернет нам словарь для исходного датасета (исходный датасет это список списков туплей).
def createOneHotDict(inputData):
    """Creates a one-hot-encoder dictionary based on the input data.

    Args:
        inputData (RDD of lists of (int, str)): An RDD of observations where each observation is
            made up of a list of (featureID, value) tuples.

    Returns:
        dict: A dictionary where the keys are (featureID, value) tuples and map to values that are
            unique integers.
    """
    distinctFeats = (inputData
        .плоский список(lambda x: x)
        .выкинуть дубли())
    res = (distinctFeats
        .сгенерить индексы()
        .собрать словарь())
    return res

sampleOHEDictAuto = createOneHotDict(sampleDataRDD)
print sampleOHEDictAuto
{(2, 'mouse'): 0, (0, 'cat'): 1, (0, 'bear'): 2, (2, 'salmon'): 3, (1, 'tabby'): 4, (1, 'black'): 5, (0, 'mouse'): 6}

На сегодня хватит, продолжим завтра.

Следующий номер программы:
Part 3: Parse CTR data and generate OHE features
Visualization 1: Feature frequency






original post http://vasnake.blogspot.com/2015/11/week-4-lab-4.html

Комментариев нет:

Отправить комментарий

Архив блога

Ярлыки

linux (241) python (191) citation (186) web-develop (170) gov.ru (159) video (124) бытовуха (115) sysadm (100) GIS (97) Zope(Plone) (88) бурчалки (84) Book (83) programming (82) грабли (77) Fun (76) development (73) windsurfing (72) Microsoft (64) hiload (62) internet provider (57) opensource (57) security (57) опыт (55) movie (52) Wisdom (51) ML (47) driving (45) hardware (45) language (45) money (42) JS (41) curse (40) bigdata (39) DBMS (38) ArcGIS (34) history (31) PDA (30) howto (30) holyday (29) Google (27) Oracle (27) tourism (27) virtbox (27) health (26) vacation (24) AI (23) Autodesk (23) SQL (23) Java (22) humor (22) knowledge (22) translate (20) CSS (19) cheatsheet (19) hack (19) Apache (16) Manager (15) web-browser (15) Никонов (15) Klaipeda (14) functional programming (14) happiness (14) music (14) todo (14) PHP (13) course (13) scala (13) weapon (13) HTTP. Apache (12) SSH (12) frameworks (12) hero (12) im (12) settings (12) HTML (11) SciTE (11) USA (11) crypto (11) game (11) map (11) HTTPD (9) ODF (9) Photo (9) купи/продай (9) benchmark (8) documentation (8) 3D (7) CS (7) DNS (7) NoSQL (7) cloud (7) django (7) gun (7) matroska (7) telephony (7) Microsoft Office (6) VCS (6) bluetooth (6) pidgin (6) proxy (6) Donald Knuth (5) ETL (5) NVIDIA (5) Palanga (5) REST (5) bash (5) flash (5) keyboard (5) price (5) samba (5) CGI (4) LISP (4) RoR (4) cache (4) car (4) display (4) holywar (4) nginx (4) pistol (4) spark (4) xml (4) Лебедев (4) IDE (3) IE8 (3) J2EE (3) NTFS (3) RDP (3) holiday (3) mount (3) Гоблин (3) кухня (3) урюк (3) AMQP (2) ERP (2) IE7 (2) NAS (2) Naudoc (2) PDF (2) address (2) air (2) british (2) coffee (2) fitness (2) font (2) ftp (2) fuckup (2) messaging (2) notify (2) sharepoint (2) ssl/tls (2) stardict (2) tests (2) tunnel (2) udev (2) APT (1) CRUD (1) Canyonlands (1) Cyprus (1) DVDShrink (1) Jabber (1) K9Copy (1) Matlab (1) Portugal (1) VBA (1) WD My Book (1) autoit (1) bike (1) cannabis (1) chat (1) concurrent (1) dbf (1) ext4 (1) idioten (1) join (1) krusader (1) license (1) life (1) migration (1) mindmap (1) navitel (1) pneumatic weapon (1) quiz (1) regexp (1) robot (1) science (1) serialization (1) spatial (1) tie (1) vim (1) Науру (1) крысы (1) налоги (1) пианино (1)