页面树结构

版本比较

标识

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。

sklearn.feature_extraction模块可用于从包含文本和图像等格式的数据集中提取机器学习算法支持的格式的特征。

 

注意

注意: 特征提取与特征选择非常不同:前者包括将任意数据(如文本或图像)转换为可用于机器学习的数值特征。后者是应用于这些功能的机器学习技术。

从类型的字典加载功能

该类DictVectorizer可用于将表示为标准Python dict对象列表的功能数组转换为由Scikit-learn估计器使用的NumPy / SciPy表示。

虽然Python的处理速度并不是特别快,但Python dict具有使用方便,稀疏(缺少功能不需要存储)以及存储功能名称等优点。

DictVectorizer实现了所谓的一个K或“一热”编码,用于分类(也称为标称,离散)特征。分类特征是“属性值”对,其中该值被限制为不排序的可能性的离散列表(例如,主题标识符,对象类型,标签,名称...)。

在下文中,“城市”是一个分类属性,而“温度”是传统的数字特征:

代码块
languagepy
>>> measurements = [
...     {'city': 'Dubai', 'temperature': 33.},
...     {'city': 'London', 'temperature': 12.},
...     {'city': 'San Fransisco', 'temperature': 18.},
... ]

>>> from sklearn.feature_extraction import DictVectorizer
>>> vec = DictVectorizer()

>>> vec.fit_transform(measurements).toarray()
array([[  1.,   0.,   0.,  33.],
       [  0.,   1.,   0.,  12.],
       [  0.,   0.,   1.,  18.]])

>>> vec.get_feature_names()
['city=Dubai', 'city=London', 'city=San Fransisco', 'temperature']

DictVectorizer 也是对于自然语言处理模型中的训练序列分类器的有用的表示变换,通常通过提取围绕特定感兴趣词的特征窗口来工作。

例如,假设我们有一个第一个算法来提取我们想要用作训练序列分类器(例如一个块)的补码的语音(PoS)标签。以下dict可以是在“坐在垫子上的猫”这个句子中围绕“sat”一词提取的一个特征窗口。

代码块
languagepy
>>> pos_window = [
...     {
...         'word-2': 'the',
...         'pos-2': 'DT',
...         'word-1': 'cat',
...         'pos-1': 'NN',
...         'word+1': 'on',
...         'pos+1': 'PP',
...     },
...     # in a real application one would extract many such dictionaries
... ]

该描述可以被矢量化为适合于馈送到分类器中的稀疏二维矩阵(可以在被管道 text.TfidfTransformer进行归一化之后):

代码块
languagepy
>>> vec = DictVectorizer()
>>> pos_vectorized = vec.fit_transform(pos_window)
>>> pos_vectorized                
<1x6 sparse matrix of type '<... 'numpy.float64'>'
    with 6 stored elements in Compressed Sparse ... format>
>>> pos_vectorized.toarray()
array([[ 1.,  1.,  1.,  1.,  1.,  1.]])
>>> vec.get_feature_names()
['pos+1=PP', 'pos-1=NN', 'pos-2=DT', 'word+1=on', 'word-1=cat', 'word-2=the']

你可以想像,如果一个文本语料库的每一个单词提取这样一个上下文,结果矩阵就会非常宽(许多一个热点),其中绝大部分时间大部分被重视为零。为了使结果数据结构能够适应内存,DictVectorizer该类scipy.sparse默认使用一个矩阵而不是一个numpy.ndarray

 

特征散列

该类FeatureHasher是使用称为特征散列的技术或“哈希技巧” 的高速,低内存向量化器 。不像在向量化器那样构建一个在训练中遇到的功能的哈希表,而是FeatureHasher 将哈希函数应用于特征,以便直接在样本矩阵中确定它们的列索引。结果是增加速度和减少内存使用,牺牲可视性; 哈希表不记得输入特征是什么样的,没有inverse_transform方法。

由于散列函数可能导致(不相关)特征之间的冲突,因此使用带符号散列函数,并且哈希值的符号确定存储在特征的输出矩阵中的值的符号。这样,碰撞可能会消除而不是累积错误,并且任何输出要素的值的预期平均值为零。

如果non_negative=True传递给构造函数,则采用绝对值。这样可以撤销一些碰撞处理,但允许将输出传递给估计器,sklearn.naive_bayes.MultinomialNB或者 sklearn.feature_selection.chi2预期为非负输入的特征选择器。

FeatureHasher接受映射(如Python dict及其在collections模块中的变体), 对或字符串,具体取决于构造函数参数。映射被视为对的列表,而单个字符串的隐含值为1,因此被解释为 。如果在样品中出现的单个特征多次,相关联的值将被相加(因此和成为)。输出始终是CSR格式的矩阵。(feature, value)input_type(feature, value)['feat1', 'feat2', 'feat3'][('feat1', 1), ('feat2', 1), ('feat3', 1)]('feat', 2)('feat', 3.5)('feat', 5.5)FeatureHasherscipy.sparse

在文档分类中可以使用特征散列,但是除了Unicode到UTF-8编码之外text.CountVectorizer, FeatureHasher不能进行字分割或任何其他预处理。请参阅使用散列技巧向下整合一个大型文本语料库,用于组合的tokenizer / hasher。

例如,考虑一个需要从对中提取的特征的单词级自然语言处理任务。可以使用Python生成器函数来提取功能:(token, part_of_speech)

代码块
languagepy
def token_features(token, part_of_speech):
    if token.isdigit():
        yield "numeric"
    else:
        yield "token={}".format(token.lower())
        yield "token,pos={},{}".format(token, part_of_speech)
    if token[0].isupper():
        yield "uppercase_initial"
    if token.isupper():
        yield "all_uppercase"
    yield "pos={}".format(part_of_speech)

然后,将raw_X要被馈送到FeatureHasher.transform 可使用被构造:

代码块
languagepy
raw_X = (token_features(tok, pos_tagger(tok)) for tok in corpus)

并喂给一个哈希尔:

代码块
languagepy
hasher = FeatureHasher(input_type='string')
X = hasher.transform(raw_X)

得到scipy.sparse矩阵X

注意使用发生器理解,它将懒惰引入特征提取中:令牌只能根据哈希尔的需求进行处理。

实现细节

FeatureHasher使用签名的32位变体的MurmurHash3。结果(并且由于限制scipy.sparse),当前支持的功能的最大数量

Weinberger等人的散文技巧的原始方法 使用两个单独的散列函数,H 分别确定特征的列索引和符号。本实现在假设MurmurHash3的符号位与其他位无关的假设下工作。

由于使用简单的模数将散列函数转换为列索引,建议使用2的幂作为n_features参数; 否则功能将不会均匀地映射到列。

参考文献:

 

文本特征提取

常用Vectorizer使用

CountVectorizer 在单个类中实现标记化和事件计数:

代码块
languagepy
>>> from sklearn.feature_extraction.text import CountVectorizer

该模型有许多参数,但默认值是相当合理的(请参阅参考文档了解详细信息):

代码块
languagepy
>>> vectorizer = CountVectorizer(min_df=1)
>>> vectorizer                     
CountVectorizer(analyzer=...'word', binary=False, decode_error=...'strict',
        dtype=<... 'numpy.int64'>, encoding=...'utf-8', input=...'content',
        lowercase=True, max_df=1.0, max_features=None, min_df=1,
        ngram_range=(1, 1), preprocessor=None, stop_words=None,
        strip_accents=None, token_pattern=...'(?u)\\b\\w\\w+\\b',
        tokenizer=None, vocabulary=None)

让我们用它来标记和计数文本文档的简约语料库的出现:

代码块
languagepy
>>> corpus = [
...     'This is the first document.',
...     'This is the second second document.',
...     'And the third one.',
...     'Is this the first document?',
... ]
>>> X = vectorizer.fit_transform(corpus)
>>> X                              
<4x9 sparse matrix of type '<... 'numpy.int64'>'
    with 19 stored elements in Compressed Sparse ... format>

默认配置通过提取至少2个字母的字符来标记字符串。可以明确地请求执行此步骤的具体功能:

代码块
languagepy
>>> analyze = vectorizer.build_analyzer()
>>> analyze("This is a text document to analyze.") == (
...     ['this', 'is', 'text', 'document', 'to', 'analyze'])
True

分配器在拟合期间发现的每个项都被分配一个对应于所得矩阵中的列的唯一整数索引。列的这种解释可以检索如下:

代码块
languagepy
>>> vectorizer.get_feature_names() == (
...     ['and', 'document', 'first', 'is', 'one',
...      'second', 'the', 'third', 'this'])
True

>>> X.toarray()           
array([[0, 1, 1, 1, 0, 0, 1, 0, 1],
       [0, 1, 0, 1, 0, 2, 1, 0, 1],
       [1, 0, 0, 0, 1, 0, 1, 1, 0],
       [0, 1, 1, 1, 0, 0, 1, 0, 1]]...)

从功能名称到列索引的相反映射存储在vocabulary_矢量化器的 属性中:

代码块
languagepy
>>> vectorizer.vocabulary_.get('document')
1

因此,在将来的调用转换方法中,在训练语料库中看不到的单词将被完全忽略:

代码块
languagepy
>>> vectorizer.transform(['Something completely new.']).toarray()
...                           
array([[0, 0, 0, 0, 0, 0, 0, 0, 0]]...)

请注意,在上一个语料库中,第一个和最后一个文档具有完全相同的单词,因此以相等的向量编码。特别是我们失去了最后一个文件是一个疑问形式的信息。为了保存一些本地的订购信息,除了1克(个别词)之外,我们还可以提取2克的单词:

代码块
languagepy
>>> bigram_vectorizer = CountVectorizer(ngram_range=(1, 2),
...                                     token_pattern=r'\b\w+\b', min_df=1)
>>> analyze = bigram_vectorizer.build_analyzer()
>>> analyze('Bi-grams are cool!') == (
...     ['bi', 'grams', 'are', 'cool', 'bi grams', 'grams are', 'are cool'])
True

因此,此向量化器提取的词汇量大得多,现在可以解决以本地定位模式编码的模糊:

代码块
languagepy
>>> X_2 = bigram_vectorizer.fit_transform(corpus).toarray()
>>> X_2
...                           
array([[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0],
       [0, 0, 1, 0, 0, 1, 1, 0, 0, 2, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0],
       [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0],
       [0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1]]...)

特别是“这是”的疑问形式仅存在于最后一份文件中:

代码块
languagepy
>>> feature_index = bigram_vectorizer.vocabulary_.get('is this')
>>> X_2[:, feature_index]     
array([0, 0, 0, 1]...)

 

Tf-idf项加权

在一个大的文本语料库中,一些单词将会非常现代(例如“the”,“a”,“is”是英文),因此对文档的实际内容没有什么有意义的信息。如果我们将直接计数数据直接提供给分类器,那么这些非常频繁的术语将会影响更少的更有趣的术语的频率。

为了将计数特征重新调整为适合分类器使用的浮点值,使用tf-idf变换是非常常见的。

TF是指术语频率而TF-IDF意味着术语频次 逆文档频率: 

使用TfidfTransformer默认设置, 术语频率,给定文档中术语出现的次数乘以idf组件,其计算方式为TfidfTransformer(norm='l2', use_idf=True, smooth_idf=True, sublinear_tf=False)

n_d文件总数在哪里,是 包含术语的文件数量Ť。然后,所得到的tf-idf向量通过欧几里得范数归一化:

这最初是用于信息检索开发的术语加权方案(作为搜索引擎结果的排名功能),也在文档分类和聚类中得到很好的利用。

以下部分包含进一步说明和示例,说明如何精确计算tf-idfs以及如何在scikit-learn中计算tf-idfs,TfidfTransformerTfidfVectorizer与定义idf的标准教科书符号略有不同

TfidfTransformerTfidfVectorizer with中smooth_idf=False,将“1”计数添加到idf而不是idf的分母:

该规范化由TfidfTransformer 类实现:

代码块
languagepy
>>> from sklearn.feature_extraction.text import TfidfTransformer
>>> transformer = TfidfTransformer(smooth_idf=False)
>>> transformer   
TfidfTransformer(norm=...'l2', smooth_idf=False, sublinear_tf=False,
                 use_idf=True)

有关所有参数的详细信息,请参阅参考文档

让我们举个例子来说说下列几点。第一个术语是100%的时间,因此不是很有趣。另外两个功能仅在不到50%的时间内,因此可能更具代表性的文件内容:

代码块
languagepy
>>> counts = [[3, 0, 1],
...           [2, 0, 0],
...           [3, 0, 0],
...           [4, 0, 0],
...           [3, 2, 0],
...           [3, 0, 2]]
...
>>> tfidf = transformer.fit_transform(counts)
>>> tfidf                         
<6x3 sparse matrix of type '<... 'numpy.float64'>'
    with 9 stored elements in Compressed Sparse ... format>

>>> tfidf.toarray()                        
array([[ 0.81940995,  0.        ,  0.57320793],
       [ 1.        ,  0.        ,  0.        ],
       [ 1.        ,  0.        ,  0.        ],
       [ 1.        ,  0.        ,  0.        ],
       [ 0.47330339,  0.88089948,  0.        ],
       [ 0.58149261,  0.        ,  0.81355169]])

每行标准化为具有单位欧几里得规范:

例如,我们可以计算计数数组中第一个文档中第一个项的tf-idf,如下所示:

现在,如果我们对文档中剩下的2个术语重复这个计算,我们得到

和原始tf-idfs的向量:

然后,应用欧几里德(L2)规范,我们获得文档1的以下tf-idfs:

此外,默认参数smooth_idf=True将“1”添加到分子和分母,就好像一个额外的文档被看到一样包含集合中的每个术语一次,这样可以避免零分割:

使用此修改,文档1中第三项的tf-idf更改为1.8473:

而L2标准化的tf-idf变为

代码块
languagepy
>>> transformer = TfidfTransformer()
>>> transformer.fit_transform(counts).toarray()
array([[ 0.85151335,  0.        ,  0.52433293],
       [ 1.        ,  0.        ,  0.        ],
       [ 1.        ,  0.        ,  0.        ],
       [ 1.        ,  0.        ,  0.        ],
       [ 0.55422893,  0.83236428,  0.        ],
       [ 0.63035731,  0.        ,  0.77630514]])

fit方法调用计算的每个特征的权重存储在模型属性中:

代码块
languagepy
>>> transformer.idf_                       
array([ 1. ...,  2.25...,  1.84...])

作为TF-IDF是经常用于文本的功能,也有另一种称为类TfidfVectorizer,它结合了所有的选项 CountVectorizer,并TfidfTransformer在一个模型:

代码块
languagepy
>>> from sklearn.feature_extraction.text import TfidfVectorizer
>>> vectorizer = TfidfVectorizer(min_df=1)
>>> vectorizer.fit_transform(corpus)
...                                
<4x9 sparse matrix of type '<... 'numpy.float64'>'
    with 19 stored elements in Compressed Sparse ... format>

虽然tf-idf标准化通常非常有用,但是可能存在二进制发生标记可能提供更好的特征的情况。这可以通过使用binary参数来实现CountVectorizer。特别地,诸如Bernoulli Naive Bayes的一些估计器 明确地建立离散布尔随机变量。而且,非常短的文本很可能具有嘈杂的tf-idf值,而二进制出现信息更稳定。

像往常一样,调整特征提取参数的最佳方法是使用交叉验证的网格搜索,例如通过将特征提取器与分类器进行流水线化:

 

解码文本文件

文本由字符组成,但文件由字节组成。这些字节表示根据某些编码的字符。要使用Python中的文本文件,它们的字节必须被解码为一个称为Unicode的字符集。通用编码有ASCII,拉丁语1(西欧),KOI8-R(俄语)和通用编码UTF-8和UTF-16。还有许多人存在

scikit-learn中的文本功能提取器知道如何解码文本文件,但只有当您告诉他们文件的编码时,CountVectorizer才能使用这个encoding参数。对于现代文本文件,正确的编码大概是UTF-8,因此它是default(encoding="utf-8")。

如果正在加载的文本实际上并没有使用UTF-8进行编码,那么您将得到一个UnicodeDecodeError。向量化器可以通过将decode_error参数设置为任意一个"ignore" 或"replace"。有关bytes.decode更多详细信息,请参阅Python函数的文档 (help(bytes.decode)在Python提示符下输入)。

如果您在解码文本时遇到问题,请尝试以下操作:

  • 了解文本的实际编码是什么。该文件可能带有标题或README,告诉您编码,或者可能有一些标准编码,您可以根据文本来自哪里。
  • 您可能可以使用UNIX命令找出它一般使用什么样的编码file。Python chardet模块附带一个脚本chardetect.py,它会猜测具体的编码,尽管你不能依靠它的猜测是正确的。
  • 您可以尝试UTF-8并忽略错误。您可以对字节字符串进行bytes.decode(errors='replace')解码,以用无意义的字符替换所有解码错误,或者decode_error='replace'在向量化器中设置 。这可能会损坏您的功能的有用性。
  • 真实文本可能来自可能使用不同编码的各种来源,或者甚至以与编码的编码不同的编码进行粗略解码。这在从Web检索的文本中是常见的。Python包ftfy可以自动整理出一些类型的解码错误,因此您可以尝试解码未知文本latin-1 ,然后使用ftfy来修复错误。
  • 如果文本是一个很简单的编码,很难整理(20个新闻组数据集的情况),你可以回到一个简单的单字节编码,如latin-1。某些文本可能显示不正确,但至少相同的字节序列将始终代表相同的功能。

例如,以下代码段使用chardet (未附带scikit学习,必须单独安装),以找出三个文本的编码。然后,它将文本向量化并打印学习的词汇。此处未显示输出。

代码块
languagepy
>>> import chardet    
>>> text1 = b"Sei mir gegr\xc3\xbc\xc3\x9ft mein Sauerkraut"
>>> text2 = b"holdselig sind deine Ger\xfcche"
>>> text3 = b"\xff\xfeA\x00u\x00f\x00 \x00F\x00l\x00\xfc\x00g\x00e\x00l\x00n\x00 \x00d\x00e\x00s\x00 \x00G\x00e\x00s\x00a\x00n\x00g\x00e\x00s\x00,\x00 \x00H\x00e\x00r\x00z\x00l\x00i\x00e\x00b\x00c\x00h\x00e\x00n\x00,\x00 \x00t\x00r\x00a\x00g\x00 \x00i\x00c\x00h\x00 \x00d\x00i\x00c\x00h\x00 \x00f\x00o\x00r\x00t\x00"
>>> decoded = [x.decode(chardet.detect(x)['encoding'])
...            for x in (text1, text2, text3)]        
>>> v = CountVectorizer().fit(decoded).vocabulary_    
>>> for term in v: print(v)    

(根据版本chardet,可能会遇到第一个错误。)

有关Unicode和字符编码的一般介绍,请参阅Joel Spolsky的绝对最小每个软件开发人员必须了解Unicode

词汇表示的限制

单词集合(一个单词是什么)不能捕获短语和多字表达,有效地忽略任何单词顺序依赖。另外,这个单词模型不能解释潜在的拼写错误或单词派生。

N克救援!而不是构建一个简单的unigrams集合(n = 1),可能更喜欢收集一组二进制(n = 2),其中计算出连续词对。

也可以考虑一个字符n-gram的集合,这种表示对拼写错误和派生有弹性。

例如,假设我们正在处理的两个文件的语料库: 。第二个文件包含“单词”一词的拼写错误。一个简单的单词表示将把这两个视为非常不同的文档,两个可能的特征都是不同的。然而,一个字符2克的表示可以找到匹配的文档中的4个特征中的4个,这可能有助于优选的分类器更好地决定:['words', 'wprds']

代码块
languagepy
>>> ngram_vectorizer = CountVectorizer(analyzer='char_wb', ngram_range=(2, 2), min_df=1)
>>> counts = ngram_vectorizer.fit_transform(['words', 'wprds'])
>>> ngram_vectorizer.get_feature_names() == (
...     [' w', 'ds', 'or', 'pr', 'rd', 's ', 'wo', 'wp'])
True
>>> counts.toarray().astype(int)
array([[1, 1, 1, 0, 1, 1, 1, 0],
       [1, 1, 0, 1, 1, 1, 0, 1]])

在上面的例子中,使用'char_wb分析器,它只能从单词边界内的字符(每侧填充空格)创建n-gram。的'char'分析仪,可替换地,产生的n-gram跨越字跨越:

代码块
languagepy
>>> ngram_vectorizer = CountVectorizer(analyzer='char_wb', ngram_range=(5, 5), min_df=1)
>>> ngram_vectorizer.fit_transform(['jumpy fox'])
...                                
<1x4 sparse matrix of type '<... 'numpy.int64'>'
   with 4 stored elements in Compressed Sparse ... format>
>>> ngram_vectorizer.get_feature_names() == (
...     [' fox ', ' jump', 'jumpy', 'umpy '])
True

>>> ngram_vectorizer = CountVectorizer(analyzer='char', ngram_range=(5, 5), min_df=1)
>>> ngram_vectorizer.fit_transform(['jumpy fox'])
...                                
<1x5 sparse matrix of type '<... 'numpy.int64'>'
    with 5 stored elements in Compressed Sparse ... format>
>>> ngram_vectorizer.get_feature_names() == (
...     ['jumpy', 'mpy f', 'py fo', 'umpy ', 'y fox'])
True

char_wb对于使用白色空间进行单词分离的语言来说,语言边界感知变体特别有趣,因为char在这种情况下,它会产生比原始变体更少的噪声特征。对于这种语言,它可以增加使用这些特征训练的分类器的预测精度和收敛速度,同时保持关于拼写错误和词导出的鲁棒性。

虽然可以通过提取n-gram而不是单个单词来保存一些本地定位信息,但是包含n-gram的单词和行袋破坏了文档的大部分内部结构,因此破坏了该内部结构的大部分含义。

为了处理自然语言理解的更广泛的任务,因此应考虑到句子和段落的地方结构。因此,许多这样的模型将被称为“结构化输出”问题,这些问题目前不在scikit学习的范围之内。

 

矢量化的大型文本语料库与哈希招

上述向量化方案是简单的,但是它存在从字符串令牌到整数特征索引( vocabulary_属性)的内存映射,这在处理大型数据集时会产生几个问题

可以通过组合由类实现的“散列技巧”(Feature hashing) sklearn.feature_extraction.FeatureHasher和文本预处理和标记化特征来克服这些限制CountVectorizer

这种组合是在HashingVectorizer一个主要与API兼容的变压器类中实现的CountVectorizer。 HashingVectorizer是无国籍的,这意味着你不必打电话fit给它:

代码块
languagepy
>>> from sklearn.feature_extraction.text import HashingVectorizer
>>> hv = HashingVectorizer(n_features=10)
>>> hv.transform(corpus)
...                                
<4x10 sparse matrix of type '<... 'numpy.float64'>'
    with 16 stored elements in Compressed Sparse ... format>

您可以看到,在矢量输出中提取了16个非零特征令牌:这小于CountVectorizer在同一玩具语料库之前提取的19个非零值。由于n_features参数值较低,差异来自哈希函数冲突。

在现实世界中,n_features参数可以保留为默认值(大约一百万个可能的特征)。如果内存或下游模型大小是选择较低值的问题,例如可能有助于在典型文本分类任务上引入太多额外的冲突。2 ** 202 ** 18

需要注意的是维不影响算法的CPU的训练时间,其对企业社会责任矩阵操作(LinearSVC(dual=True)PerceptronSGDClassifierPassiveAggressive),但它确实为与CSC矩阵(工作算法LinearSVC(dual=False)Lasso()等等)。

让我们再次尝试使用默认设置:

代码块
languagepy
>>> hv = HashingVectorizer()
>>> hv.transform(corpus)
...                               
<4x1048576 sparse matrix of type '<... 'numpy.float64'>'
    with 19 stored elements in Compressed Sparse ... format>

我们不再得到碰撞,但这是以牺牲更大尺寸的输出空间为代价的。当然,这里使用的其他术语可能还会相互冲突。

HashingVectorizer还带有以下限制:

  • inverse_transform由于执行映射的哈希函数的单向特性,不可能反转模型(无方法),也不能访问特征的原始字符串表示。
  • 它不提供IDF权重,因为这将引入模型中的状态。TfidfTransformer如果需要,可以在管道中附加A。

使用HashingVectorizer执行外核缩放

使用a的一个有趣的开发HashingVectorizer是执行外核缩放的能力。这意味着我们可以从不符合计算机主内存的数据中学习。

实现核心外扩展的策略是将数据以小批量流式传输到估计器。每个小批量都是使用矢量化的HashingVectorizer ,以保证估计器的输入空间总是具有相同的维度。因此,随时使用的内存量由小批量的大小限制。虽然使用这种方法可以摄取的数据量没有限制,但从实际的角度来看,学习时间通常受到CPU任务花费的时间的限制。

对于文本分类任务中的外核缩放的完整示例,请参阅文本文档的外核分类

自定义矢量化器类

可以通过将可调用传递给向量化程序构造函数来定制行为:

代码块
languagepy
>>> def my_tokenizer(s):
...     return s.split()
...
>>> vectorizer = CountVectorizer(tokenizer=my_tokenizer)
>>> vectorizer.build_analyzer()(u"Some... punctuation!") == (
...     ['some...', 'punctuation!'])
True

特别是我们命名:

(Lucene用户可能会识别这些名称,但请注意,scikit学习概念可能无法一对一映射到Lucene概念上。)

为了使预处理,分词器和分析器知道模型参数,可以从类派生并重写的 build_preprocessorbuild_tokenizer`build_analyzer 工厂方法,而不是通过自定义功能。

一些提示和技巧:

在处理不使用显式字分隔符(例如空格)的亚洲语言时,自定义向量化器也是有用的。

 

图像特征提取

4.2.4.1。补丁提取

补丁提取

extract_patches_2d功能从存储为二维数组的图像或沿着第三轴的颜色信息三维提取补丁。要从其所有补丁重建图像,请使用 reconstruct_from_patches_2d。例如,让使用生成一个4x4像素的图像与3个彩色通道(例如RGB格式):

代码块
languagepy
>>> import numpy as np
>>> from sklearn.feature_extraction import image

>>> one_image = np.arange(4 * 4 * 3).reshape((4, 4, 3))
>>> one_image[:, :, 0]  # R channel of a fake RGB picture
array([[ 0,  3,  6,  9],
       [12, 15, 18, 21],
       [24, 27, 30, 33],
       [36, 39, 42, 45]])

>>> patches = image.extract_patches_2d(one_image, (2, 2), max_patches=2,
...     random_state=0)
>>> patches.shape
(2, 2, 2, 3)
>>> patches[:, :, :, 0]
array([[[ 0,  3],
        [12, 15]],

       [[15, 18],
        [27, 30]]])
>>> patches = image.extract_patches_2d(one_image, (2, 2))
>>> patches.shape
(9, 2, 2, 3)
>>> patches[4, :, :, 0]
array([[15, 18],
       [27, 30]])

 

现在让我们尝试通过对重叠区域进行平均来从补丁重建原始图像:

代码块
languagepy
>>> reconstructed = image.reconstruct_from_patches_2d(patches, (4, 4, 3))
>>> np.testing.assert_array_equal(one_image, reconstructed)

 

PatchExtractor以同样的方式类作品 extract_patches_2d,只是它支持多种图像作为输入。它被实现为一个估计器,因此可以在管道中使用。看到:

代码块
languagepy
>>> five_images = np.arange(5 * 4 * 4 * 3).reshape(5, 4, 4, 3)
>>> patches = image.PatchExtractor((2, 2)).transform(five_images)
>>> patches.shape
(45, 2, 2, 3)
 

图像的连接图

scikit-learn中的几个估计可以使用特征或样本之间的连接信息。例如,Ward聚类(分层聚类)可以仅聚集在图像的相邻像素上,从而形成连续的补丁:

为此,估计器使用“连接”矩阵,给出哪些样本被连接。

该函数img_to_graph从2D或3D图像返回这样一个矩阵。类似地,grid_to_graph为给定这些图像的形状的图像构建连接矩阵。

这些矩阵可用于在使用连通性信息的估计器(如Ward聚类(分层聚类))中强制连接,而且还可构建预计算内核或相似矩阵。