单热编码:列出成员资格错误

时间:2017-08-21 20:00:23

标签: python python-3.x numpy one-hot-encoding

给定可变数量的字符串,我想对它们进行单热编码,如下例所示:

s1 = 'awaken my love'
s2 = 'awaken the beast'
s3 = 'wake beast love'

# desired result - NumPy array
array([[ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 1.,  0.,  0.,  1.,  1.,  0.],
       [ 0.,  0.,  1.,  0.,  1.,  1.]])

当前代码:

def uniquewords(*args):
    """Create order-preserved string with unique words between *args"""
    allwords = ' '.join(args).split()
    return ' '.join(sorted(set(allwords), key=allwords.index)).split()

def encode(*args):
    """One-hot encode the given input strings"""
    unique = uniquewords(*args)
    feature_vectors = np.zeros((len(args), len(unique)))
    for vec, s in zip(feature_vectors, args):
        for num, word in enumerate(unique):                
            vec[num] = word in s
    return feature_vectors

问题出在这一行:

vec[num] = word in s

例如,'wake' in 'awaken my love'选择True作为print(encode(s1, s2, s3)) [[ 1. 1. 1. 0. 0. 1.] [ 1. 0. 0. 1. 1. 1.] [ 0. 0. 1. 0. 1. 1.]] (这是正确的,但不是我的需要),并提供以下略有结果的结果:

re

我使用{ "categories": [ { "id": 1, "name": "cat1", "topics": [ { "$ref": "#/topics/1" } ] } ], "topics": [ { "id": 1, "name": "top1" } ] } 看过a solution,但我不确定如何在此处申请。我怎样才能纠正上面的单线? (摆脱嵌套循环也不错,但我不会要求进行一般的代码编辑,除非提供它。)

4 个答案:

答案 0 :(得分:2)

这是一种方法 -

def membership(list_strings):
    split_str = [i.split(" ") for i in list_strings]
    split_str_unq = np.unique(np.concatenate(split_str))
    out = np.array([np.in1d(split_str_unq, b_i) for b_i in split_str]).astype(int)
    df_out = pd.DataFrame(out, columns = split_str_unq)
    return df_out

示例运行 -

In [189]: s1 = 'awaken my love'
     ...: s2 = 'awaken the beast'
     ...: s3 = 'wake beast love'
     ...: 

In [190]: membership([s1,s2,s3])
Out[190]: 
   awaken  beast  love  my  the  wake
0       1      0     1   1    0     0
1       1      1     0   0    1     0
2       0      1     1   0    0     1

这是另一个使用np.searchsorted来获取每行的列索引以设置到输出数组并希望更快 -

def membership_v2(list_strings):
    split_str = [i.split(" ") for i in list_strings]
    all_strings = np.concatenate(split_str)
    split_str_unq = np.unique(all_strings)
    col = np.searchsorted(split_str_unq, all_strings)
    row = np.repeat(np.arange(len(split_str)) , [len(i) for i in split_str])
    out = np.zeros((len(split_str),col.max()+1),dtype=int)
    out[row, col] = 1
    df_out = pd.DataFrame(out, columns = split_str_unq)
    return df_out

请注意,作为数据帧的输出主要是为了更好/更容易地表示输出。

答案 1 :(得分:1)

如果你进行轻微的重构,以便将每个句子视为一个单词列表,它会删除你需要做的很多splitjoin,并使word in s的行为有点自然化。但是,set是成员资格测试的首选,因为它可以在O(1)中执行此操作,并且您应该只为迭代的每个参数构造一个,因此您的代码将导致此:

import numpy as np
import itertools

def uniquewords(*args):
    """Create order-preserved string with unique words between *args"""
    allwords = list(itertools.chain(*args))
    return sorted(set(allwords), key=allwords.index)

def encode(*args):
    """One-hot encode the given input strings"""
    args_with_words = [arg.split() for arg in args]
    unique = uniquewords(*args_with_words)
    feature_vectors = np.zeros((len(args), len(unique)))
    for vec, s in zip(feature_vectors, args_with_words):
        s_set = set(s)
        for num, word in enumerate(unique):                
            vec[num] = word in s_set
    return feature_vectors

print encode("awaken my love", "awaken the beast", "wake beast love")

正确输出

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

一旦你完成了这项工作,你可能会发现自己根本不需要进行成员资格测试,而且你只需要对s进行迭代,只需要为需要设置为{{1}的单词烦恼}。这种方法可能比较大的数据集快得多。

1

答案 2 :(得分:1)

您可以使用pandas从列表列表中创建一个热门的编码转换(例如,每个字符串随后被拆分为单词列表的字符串列表)。

import pandas as pd

s1 = 'awaken my love'
s2 = 'awaken the beast'
s3 = 'wake beast love'

words = pd.Series([s1, s2, s3])
df = pd.melt(words.str.split().apply(pd.Series).reset_index(), 
             value_name='word', id_vars='index')
result = (
    pd.concat([df['index'], pd.get_dummies(df['word'])], axis=1)
    .groupby('index')
    .any()
).astype(float)
>>> result
       awaken  beast  love  my  the  wake
index                                    
0           1      0     1   1    0     0
1           1      1     0   0    1     0
2           0      1     1   0    0     1

>>> result.values
array([[ 1.,  0.,  1.,  1.,  0.,  0.],
       [ 1.,  1.,  0.,  0.,  1.,  0.],
       [ 0.,  1.,  1.,  0.,  0.,  1.]])

<强>解释

首先,从您的单词列表中创建一个系列。

然后将单词拆分成列并重置索引:

>>> words.str.split().apply(pd.Series).reset_index()
# Output:
#    index       0      1      2
# 0      0  awaken     my   love
# 1      1  awaken    the  beast
# 2      2    wake  beast   love

然后熔化上面的中间数据帧,结果如下:

   index variable    word
0      0        0  awaken
1      1        0  awaken
2      2        0    wake
3      0        1      my
4      1        1     the
5      2        1   beast
6      0        2    love
7      1        2   beast
8      2        2    love

get_dummies应用于单词并将结果连接到其索引位置。然后,生成的数据框在index上分组,any用于聚合(所有值均为零或一,因此any表示该单词是否有一个或多个实例)。这将返回一个布尔矩阵,该矩阵将转换为浮点数。要返回numpy数组,请将.values应用于结果。

答案 3 :(得分:0)

Set将使in运算符平均在O(1)中运行。

变化:

vec[num] = word in s

为:

vec[num] = word in set(s.split())

最终版本:

def encode(*args):
    """One-hot encode the given input strings"""
    unique = uniquewords(*args)
    feature_vectors = np.zeros((len(args), len(unique)))
    for vec, s in zip(feature_vectors, args):
        for num, word in enumerate(unique):
            vec[num] = word in set(s.split())
    return feature_vectors

结果:

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