Эффективный способ заменить строки в списке списков на основе диктов - PullRequest
1 голос
/ 21 октября 2019

У меня есть список списков, которые содержат классификационные метки для определенного домена. Пример:

data = [
    ['polmone', 'linfonodi'],
    ['osso'],
    ['polmone'],
    ['linfonodi', 'osso', 'polmone'],
    ['peritoneo', 'osso'],
    ['fegato'],
    ['polmone', 'linfonodi'],
    ['osso'],
    ['osso', 'fegato'],
]

Список содержит 331 список, и каждый из них может содержать одну или все возможные метки. Число возможных меток равно 20.

Мне нужно передать список списков меток в sklearn.neighbors.KNeighborsClassifier, и я думал о преобразовании каждой возможной метки в число (например, 0-19).

Мне было интересно узнать о наиболее эффективном способе выполнения этого преобразования.

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

{'polmone': 0, 'linfonodi': 1, ..., 'label_19': 19}

... а затем переберите каждый элемент списка и выполните str.replace().

Я считаю, что должно быть более эффективное решение. Вы что-нибудь посоветуете?

Заранее спасибо.

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

Редактировать:

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

Теперь я хочу поделиться другим решением, которое я только что нашел, когда имел дело с KNeighborClassifier и целью с несколькими выходами. Подавая закодированные метки (как строки или целые числа, так и простые списки или массивы), я получил следующую ошибку:

Traceback (most recent call last):
  File "embedding_gensim.py", line 111, in <module>
    neigh.fit(doc_train, labls_train)
  File "/home/matteo/anaconda3/envs/deep_l/lib/python3.7/site-packages/sklearn/neighbors/base.py", line 906, in fit
    check_classification_targets(y)
  File "/home/matteo/anaconda3/envs/deep_l/lib/python3.7/site-packages/sklearn/utils/multiclass.py", line 169, in check_classification_targets
    raise ValueError("Unknown label type: %r" % y_type)
ValueError: Unknown label type: 'unknown'

Я обнаружил, что MultiLabelBinarizer решает проблему подачиклассификатор со списком списков с несколькими метками (или массивами).

Итак, следуя решению @Assander Rossa:

binarized_labels = MultiLabelBinarizer().fit_transform(encoded_labels_list)

binarized_labels тогда выглядит так:

[0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0]
...

MultiLabelBinarizer() фактически работает непосредственно со списками строк вsplit_labels. Возможно, я решаю проблему с неправильной точки зрения.

Ответы [ 3 ]

2 голосов
/ 21 октября 2019

Что вы можете сделать, это использовать LabelEncoder для создания словаря:

from sklearn.preprocessing import LabelEncoder
label_encoder = LabelEncoder()
labels = ['polmone', 'fegato', 'linfonodi']
encoded_labels = label_encoder.fit_transform(labels)
labels_dict = {}
for i in range(len(labels)):
    labels_dict[labels[i]] = encoded_labels[i]

print(labels_dict)

Это дает вам {'polmone': 2, 'fegato': 0, 'linfonodi': 1}.

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

Тогда все ваше решение может выглядеть примерно так:

from sklearn.preprocessing import LabelEncoder

data = [
    ['polmone', 'linfonodi'],
    ['osso'],
    ['polmone'],
    ['linfonodi', 'osso', 'polmone'],
    ['peritoneo', 'osso'],
    ['fegato'],
    ['polmone', 'linfonodi'],
    ['osso'],
    ['osso', 'fegato'],
]

# get labels programatically from your data
labels = []
for nested_list in data:
    for label in nested_list:
        if label not in labels:
            labels.append(label)

label_encoder = LabelEncoder()
encoded_labels = label_encoder.fit_transform(labels)
labels_dict = {}
for i in range(len(labels)):
    labels_dict[labels[i]] = encoded_labels[i]

encoded_data = []
for labels_list in data:
    # for each label in a nested list replace it with the encoded value from dict
    encoded_data_list = [l.replace(l, str(labels_dict[l])) for l in labels_list]
    encoded_data.append(encoded_data_list)

Закодированные данные для предоставленных вами данных будут выглядетьэто:

>>> encoded_data
[['4', '1'], ['2'], ['4'], ['1', '2', '4'], ['3', '2'], ['0'], ['4', '1'], ['2'], ['2', '0']]
1 голос
/ 21 октября 2019

Я думаю, что Кодировщик меток - это то, что вам нужно.

Как указано в документе, эта библиотека эффективно преобразует ваши метки в целочисленную последовательность.

Что выдолжен сделать что-то вроде:

from sklearn.preprocessing import LabelEncoder
labelencoder = LabelEncoder()
labelencoder.fit(["label1", "label2", ...])
for curr_labels_list in all_labels_list:
    res = labelencoder.fit_transform(curr_labels_list)
1 голос
/ 21 октября 2019

Это работает для меня:

pandas.factorize (['B', 'C', 'D', 'B']) [0]

Вывод:

[0, 1, 2, 0]

Попробуйте также взглянуть на горячее кодирование и преобразовать категориальное в числовое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...