Как вы представляете записи данных, содержащие нечисловые элементы, как векторы (математические, НЕ c ++ вектор)? - PullRequest
2 голосов
/ 09 апреля 2011

Многие алгоритмы / стратегии интеллектуального анализа данных используют векторное представление записей данных для имитации пространственного представления данных (как машины опорных векторов).

Моя проблема связана с тем, как представлять нечисловые элементы в наборе данных. Моей первой мыслью было «псевдоним» каждого возможного значения для объекта с числом от 1 до n (где n - количество объектов).

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

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

Ответы [ 2 ]

0 голосов
/ 18 июля 2011

Я не знаю «широко принятого ответа», он полностью зависит от того, что вы хотите.

Основная идея вашего поста заключается в том, что тривиальное представление состояния памяти может быть слишком интенсивным. Например, чтобы сохранить значение, которое может иметь не более четырех состояний, вы будете использовать int (32 бита), но вы можете справиться только с 2 битами, то есть в 16 раз меньше.

Однако, чем умнее ваше представление вектора (т. Е. Компактное), тем больше времени вам потребуется для его кодирования / декодирования из / в тривиальное представление.

Я выполнил проект, в котором представлял состояние платы Connect-4 с двумя двойными (64 битами), где каждая двойная кодировала диски, принадлежащие каждому игроку. Это было огромное улучшение по сравнению с сохранением состояния в виде 42 целых чисел! Я мог бы исследовать намного дальше, имея меньший след памяти. Как правило, это то, что вы хотите.

Благодаря умелому пониманию Connect-4 можно кодировать его только одним двойным символом! Я попробовал это, и программа ооочень долго, что я вернулся к использованию 2 двойных вместо одного. Программа проводила большую часть своего времени в функциях кодирования / декодирования. Обычно это то, что вы не хотите.

Теперь, поскольку вы хотите получить ответ, есть несколько рекомендаций:

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

  • Объедините все небольшие функции (от 3 до 256 возможных значений) в примитивных типах, таких как int, double, long double или в любом другом языке. Затем запишите функции для кодирования / декодирования, используя операторы битового сдвига для скорости, если это возможно.

  • Сохранять функции, которые могут иметь «множество» (более 256) возможных значений, как есть.

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

TL; DR: есть компромисс между потреблением памяти и скоростью. Вам нужно отрегулировать в соответствии с вашей проблемой

0 голосов
/ 18 июля 2011

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

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

  1. пол / пол

  2. канал сбора

  3. уровень участия в форуме

  4. тип учетной записи

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

# column headers of raw data--all fields are categorical ('factors')
col_headers = ['sex', 'acquisition_channel', 'forum_participation_level', 'account_type']

# a single data row represents one user
row1 = ['M', 'organic_search', 'moderator', 'premium_subscriber']

# expand data matrix width-wise by adding new fields (columns) for each factor level:
input_fields = [ 'male', 'female', 'new', 'trusted', 'active_participant', 'moderator', 
                 'direct_typein', 'organic_search', 'affiliate', 'premium_subscriber',   
                 'regular_subscriber',  'unregistered_user' ]

# now, original 'row1' above, becomes (for input to ML algorithm, etc.)
warehoused_row1 = [1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0]

Этот метод преобразования кажется мне более разумным, чем хранение каждой переменной в виде одного столбца.Например, если вы сделаете последнее, то вам придется согласовать три типа каналов сбора данных с их числовым представлением - т. Е. Если органический поиск равен "1", то аффилированным лицом должно быть 2, а direct_type в 3 или наоборот?

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

для этого типа работы iиспользуйте библиотеки числовых вычислений NumPy и SciPy .

из интерактивной подсказки Python:

>>> # create two data rows, representing two unique visitors to a Web site:

>>> row1 = NP.array([0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0])

>>> row2 = NP.array([1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0])

>>> row1.dtype
  dtype('int64')
>>> row1.itemsize
  8

>>> # these two data arrays can be converted from int/float to boolean, substantially 
>>> # reducing their size w/ concomitant performance improvement
>>> row1 = NP.array(row1, dtype=bool)
>>> row2 = NP.array(row2, dtype=bool)

>>> row1.dtype
  dtype('bool')
>>> row1.itemsize    # compare with row1.itemsize = 8, above
  1

>>> # element-wise comparison of two data vectors (two users) is straightforward:
>>> row1 == row2  # element-wise comparison
  array([False, False, False, False,  True,  True, False,  True,  True, False], dtype=bool)
>>> NP.sum(row1==row2)
  5

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

def tanimoto_bool(A, B) :
    AuB = NP.sum(A==B)
    numer = AuB
    denom = len(A) + len(B) - AuB
    return numer/float(denom)

>>> tanimoto_bool(row1, row2)
  0.25
...