Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 一个热编码:列表成员资格错误_Python_Python 3.x_Numpy_One Hot Encoding - Fatal编程技术网

Python 一个热编码:列表成员资格错误

Python 一个热编码:列表成员资格错误,python,python-3.x,numpy,one-hot-encoding,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.]])

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

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
例如,“唤醒我的爱”中的“唤醒”被选为“真实的”(正确的选择,但不是为了我的需要),并给出以下稍微偏离的结果:

print(encode(s1, s2, s3))
[[ 1.  1.  1.  0.  0.  1.]
 [ 1.  0.  0.  1.  1.  1.]
 [ 0.  0.  1.  0.  1.  1.]]

我见过使用
re
,但不知道如何在这里应用。如何更正上面的一行?(摆脱嵌套循环也很好,但我不要求进行常规代码编辑,除非有人愿意提供。)

一个集合将使in操作符平均在O(1)中运行

更改:

vec[num] = word in s
致:

最终版本:

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.]]

如果你做一个轻微的重构,把每一个句子当作一个经过深思熟虑的单词列表,它会删除很多你必须做的
split
ing和
join
ing,并稍微自然化
word在s
中的行为。但是,成员资格测试首选
,因为它可以在
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
的单词。这种方法在更大的数据集上可能要快得多

import numpy as np
import itertools

def uniquewords(*args):
    """Dictionary of words to their indices in the matrix"""
    words = {}
    n = 0
    for word in itertools.chain(*args):
        if word not in words:
            words[word] = n
            n += 1
    return words

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):
        for word in s:                
            vec[unique[word]] = 1
    return feature_vectors

print encode("awaken my love", "awaken the beast", "wake beast love")
这里有一种方法-

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

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

您可以使用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
,并将结果连接到它们的索引位置。然后,将生成的datatframe分组到
索引上,并在聚合上使用
any
(所有值都是零或一,因此
any
指示该单词是否有一个或多个实例)。这将返回一个布尔矩阵,该矩阵将转换为浮点数。若要返回numpy数组,请对结果应用
.values

s中的word
未测试['awake']中的
'wake'。
。它正在测试《觉醒》中的《觉醒》(嗯,《唤醒我的爱人》中的《觉醒》或者《唤醒野兽》中的《觉醒》
)中的《觉醒》)对字符串的一组单词而不是字符串执行《觉醒》中的《觉醒》测试……什么?不,您已经具备了将字符串转换为一组单词的逻辑。只是使用它有点不同。我不是说将集合的
str
表示形式转换回集合。默认情况下,字符串在空格上拆分:
word in s.split()
已更改。虽然显式优于隐式:),但不确定这是否适用于此处。可读性应始终优先。后者更具可读性。你的
v2
版本确实非常快。所有答案都很优雅,但我接受这个答案,因为它比numpy方法快4倍,而且解释得也很好。
   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