Xgboost: feature_names incompatíveis ao usar matrizes esparsas em Python

Criado em 31 mai. 2016  ·  51Comentários  ·  Fonte: dmlc/xgboost

Estou recebendo ValueError: incompatibilidade de feature_names ao treinar xgboost com matrizes esparsas em python.
A versão do xgboost é a mais recente do git. Versões mais antigas não apresentam esse erro. O erro é retornado durante o tempo de previsão.

código

from scipy import sparse
import xgboost as xgb
from random import *
randBinList = lambda n: [randint(0,1) for b in range(1,n+1)]

train = sparse.rand(100,500)
test = sparse.rand(10, 500)
y = randBinList(100)
clf = xgb.XGBClassifier()
clf.fit(train,y)
preds = clf.predict_proba(test)

Rastreamento completo:

ValueError                                Traceback (most recent call last)
<ipython-input-15-e03f10289bf1> in <module>()
----> 1 preds = clf.predict_proba(test)

/usr/local/lib/python2.7/dist-packages/xgboost-0.4-py2.7.egg/xgboost/sklearn.pyc in predict_proba(self, data, output_margin, ntree_limit)
    471         class_probs = self.booster().predict(test_dmatrix,
    472                                              output_margin=output_margin,
--> 473                                              ntree_limit=ntree_limit)
    474         if self.objective == "multi:softprob":
    475             return class_probs

/usr/local/lib/python2.7/dist-packages/xgboost-0.4-py2.7.egg/xgboost/core.pyc in predict(self, data, output_margin, ntree_limit, pred_leaf)
    937             option_mask |= 0x02
    938 
--> 939         self._validate_features(data)
    940 
    941         length = ctypes.c_ulong()

/usr/local/lib/python2.7/dist-packages/xgboost-0.4-py2.7.egg/xgboost/core.pyc in _validate_features(self, data)
   1177 
   1178                 raise ValueError(msg.format(self.feature_names,
-> 1179                                             data.feature_names))
   1180 
   1181     def get_split_value_histogram(self, feature, fmap='', bins=None, as_pandas=True):

ValueError: feature_names mismatch: ['f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f20', 'f21', 'f22', 'f23', 'f24', 'f25', 'f26', 'f27', 'f28', 'f29', 'f30', 'f31', 'f32', 'f33', 'f34', 'f35', 'f36', 'f37', 'f38', 'f39', 'f40', 'f41', 'f42', 'f43', 'f44', 'f45', 'f46', 'f47', 'f48', 'f49', 'f50', 'f51', 'f52', 'f53', 'f54', 'f55', 'f56', 'f57', 'f58', 'f59', 'f60', 'f61', 'f62', 'f63', 'f64', 'f65', 'f66', 'f67', 'f68', 'f69', 'f70', 'f71', 'f72', 'f73', 'f74', 'f75', 'f76', 'f77', 'f78', 'f79', 'f80', 'f81', 'f82', 'f83', 'f84', 'f85', 'f86', 'f87', 'f88', 'f89', 'f90', 'f91', 'f92', 'f93', 'f94', 'f95', 'f96', 'f97', 'f98', 'f99', 'f100', 'f101', 'f102', 'f103', 'f104', 'f105', 'f106', 'f107', 'f108', 'f109', 'f110', 'f111', 'f112', 'f113', 'f114', 'f115', 'f116', 'f117', 'f118', 'f119', 'f120', 'f121', 'f122', 'f123', 'f124', 'f125', 'f126', 'f127', 'f128', 'f129', 'f130', 'f131', 'f132', 'f133', 'f134', 'f135', 'f136', 'f137', 'f138', 'f139', 'f140', 'f141', 'f142', 'f143', 'f144', 'f145', 'f146', 'f147', 'f148', 'f149', 'f150', 'f151', 'f152', 'f153', 'f154', 'f155', 'f156', 'f157', 'f158', 'f159', 'f160', 'f161', 'f162', 'f163', 'f164', 'f165', 'f166', 'f167', 'f168', 'f169', 'f170', 'f171', 'f172', 'f173', 'f174', 'f175', 'f176', 'f177', 'f178', 'f179', 'f180', 'f181', 'f182', 'f183', 'f184', 'f185', 'f186', 'f187', 'f188', 'f189', 'f190', 'f191', 'f192', 'f193', 'f194', 'f195', 'f196', 'f197', 'f198', 'f199', 'f200', 'f201', 'f202', 'f203', 'f204', 'f205', 'f206', 'f207', 'f208', 'f209', 'f210', 'f211', 'f212', 'f213', 'f214', 'f215', 'f216', 'f217', 'f218', 'f219', 'f220', 'f221', 'f222', 'f223', 'f224', 'f225', 'f226', 'f227', 'f228', 'f229', 'f230', 'f231', 'f232', 'f233', 'f234', 'f235', 'f236', 'f237', 'f238', 'f239', 'f240', 'f241', 'f242', 'f243', 'f244', 'f245', 'f246', 'f247', 'f248', 'f249', 'f250', 'f251', 'f252', 'f253', 'f254', 'f255', 'f256', 'f257', 'f258', 'f259', 'f260', 'f261', 'f262', 'f263', 'f264', 'f265', 'f266', 'f267', 'f268', 'f269', 'f270', 'f271', 'f272', 'f273', 'f274', 'f275', 'f276', 'f277', 'f278', 'f279', 'f280', 'f281', 'f282', 'f283', 'f284', 'f285', 'f286', 'f287', 'f288', 'f289', 'f290', 'f291', 'f292', 'f293', 'f294', 'f295', 'f296', 'f297', 'f298', 'f299', 'f300', 'f301', 'f302', 'f303', 'f304', 'f305', 'f306', 'f307', 'f308', 'f309', 'f310', 'f311', 'f312', 'f313', 'f314', 'f315', 'f316', 'f317', 'f318', 'f319', 'f320', 'f321', 'f322', 'f323', 'f324', 'f325', 'f326', 'f327', 'f328', 'f329', 'f330', 'f331', 'f332', 'f333', 'f334', 'f335', 'f336', 'f337', 'f338', 'f339', 'f340', 'f341', 'f342', 'f343', 'f344', 'f345', 'f346', 'f347', 'f348', 'f349', 'f350', 'f351', 'f352', 'f353', 'f354', 'f355', 'f356', 'f357', 'f358', 'f359', 'f360', 'f361', 'f362', 'f363', 'f364', 'f365', 'f366', 'f367', 'f368', 'f369', 'f370', 'f371', 'f372', 'f373', 'f374', 'f375', 'f376', 'f377', 'f378', 'f379', 'f380', 'f381', 'f382', 'f383', 'f384', 'f385', 'f386', 'f387', 'f388', 'f389', 'f390', 'f391', 'f392', 'f393', 'f394', 'f395', 'f396', 'f397', 'f398', 'f399', 'f400', 'f401', 'f402', 'f403', 'f404', 'f405', 'f406', 'f407', 'f408', 'f409', 'f410', 'f411', 'f412', 'f413', 'f414', 'f415', 'f416', 'f417', 'f418', 'f419', 'f420', 'f421', 'f422', 'f423', 'f424', 'f425', 'f426', 'f427', 'f428', 'f429', 'f430', 'f431', 'f432', 'f433', 'f434', 'f435', 'f436', 'f437', 'f438', 'f439', 'f440', 'f441', 'f442', 'f443', 'f444', 'f445', 'f446', 'f447', 'f448', 'f449', 'f450', 'f451', 'f452', 'f453', 'f454', 'f455', 'f456', 'f457', 'f458', 'f459', 'f460', 'f461', 'f462', 'f463', 'f464', 'f465', 'f466', 'f467', 'f468', 'f469', 'f470', 'f471', 'f472', 'f473', 'f474', 'f475', 'f476', 'f477', 'f478', 'f479', 'f480', 'f481', 'f482', 'f483', 'f484', 'f485', 'f486', 'f487', 'f488', 'f489', 'f490', 'f491', 'f492', 'f493', 'f494', 'f495', 'f496', 'f497', 'f498'] ['f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f20', 'f21', 'f22', 'f23', 'f24', 'f25', 'f26', 'f27', 'f28', 'f29', 'f30', 'f31', 'f32', 'f33', 'f34', 'f35', 'f36', 'f37', 'f38', 'f39', 'f40', 'f41', 'f42', 'f43', 'f44', 'f45', 'f46', 'f47', 'f48', 'f49', 'f50', 'f51', 'f52', 'f53', 'f54', 'f55', 'f56', 'f57', 'f58', 'f59', 'f60', 'f61', 'f62', 'f63', 'f64', 'f65', 'f66', 'f67', 'f68', 'f69', 'f70', 'f71', 'f72', 'f73', 'f74', 'f75', 'f76', 'f77', 'f78', 'f79', 'f80', 'f81', 'f82', 'f83', 'f84', 'f85', 'f86', 'f87', 'f88', 'f89', 'f90', 'f91', 'f92', 'f93', 'f94', 'f95', 'f96', 'f97', 'f98', 'f99', 'f100', 'f101', 'f102', 'f103', 'f104', 'f105', 'f106', 'f107', 'f108', 'f109', 'f110', 'f111', 'f112', 'f113', 'f114', 'f115', 'f116', 'f117', 'f118', 'f119', 'f120', 'f121', 'f122', 'f123', 'f124', 'f125', 'f126', 'f127', 'f128', 'f129', 'f130', 'f131', 'f132', 'f133', 'f134', 'f135', 'f136', 'f137', 'f138', 'f139', 'f140', 'f141', 'f142', 'f143', 'f144', 'f145', 'f146', 'f147', 'f148', 'f149', 'f150', 'f151', 'f152', 'f153', 'f154', 'f155', 'f156', 'f157', 'f158', 'f159', 'f160', 'f161', 'f162', 'f163', 'f164', 'f165', 'f166', 'f167', 'f168', 'f169', 'f170', 'f171', 'f172', 'f173', 'f174', 'f175', 'f176', 'f177', 'f178', 'f179', 'f180', 'f181', 'f182', 'f183', 'f184', 'f185', 'f186', 'f187', 'f188', 'f189', 'f190', 'f191', 'f192', 'f193', 'f194', 'f195', 'f196', 'f197', 'f198', 'f199', 'f200', 'f201', 'f202', 'f203', 'f204', 'f205', 'f206', 'f207', 'f208', 'f209', 'f210', 'f211', 'f212', 'f213', 'f214', 'f215', 'f216', 'f217', 'f218', 'f219', 'f220', 'f221', 'f222', 'f223', 'f224', 'f225', 'f226', 'f227', 'f228', 'f229', 'f230', 'f231', 'f232', 'f233', 'f234', 'f235', 'f236', 'f237', 'f238', 'f239', 'f240', 'f241', 'f242', 'f243', 'f244', 'f245', 'f246', 'f247', 'f248', 'f249', 'f250', 'f251', 'f252', 'f253', 'f254', 'f255', 'f256', 'f257', 'f258', 'f259', 'f260', 'f261', 'f262', 'f263', 'f264', 'f265', 'f266', 'f267', 'f268', 'f269', 'f270', 'f271', 'f272', 'f273', 'f274', 'f275', 'f276', 'f277', 'f278', 'f279', 'f280', 'f281', 'f282', 'f283', 'f284', 'f285', 'f286', 'f287', 'f288', 'f289', 'f290', 'f291', 'f292', 'f293', 'f294', 'f295', 'f296', 'f297', 'f298', 'f299', 'f300', 'f301', 'f302', 'f303', 'f304', 'f305', 'f306', 'f307', 'f308', 'f309', 'f310', 'f311', 'f312', 'f313', 'f314', 'f315', 'f316', 'f317', 'f318', 'f319', 'f320', 'f321', 'f322', 'f323', 'f324', 'f325', 'f326', 'f327', 'f328', 'f329', 'f330', 'f331', 'f332', 'f333', 'f334', 'f335', 'f336', 'f337', 'f338', 'f339', 'f340', 'f341', 'f342', 'f343', 'f344', 'f345', 'f346', 'f347', 'f348', 'f349', 'f350', 'f351', 'f352', 'f353', 'f354', 'f355', 'f356', 'f357', 'f358', 'f359', 'f360', 'f361', 'f362', 'f363', 'f364', 'f365', 'f366', 'f367', 'f368', 'f369', 'f370', 'f371', 'f372', 'f373', 'f374', 'f375', 'f376', 'f377', 'f378', 'f379', 'f380', 'f381', 'f382', 'f383', 'f384', 'f385', 'f386', 'f387', 'f388', 'f389', 'f390', 'f391', 'f392', 'f393', 'f394', 'f395', 'f396', 'f397', 'f398', 'f399', 'f400', 'f401', 'f402', 'f403', 'f404', 'f405', 'f406', 'f407', 'f408', 'f409', 'f410', 'f411', 'f412', 'f413', 'f414', 'f415', 'f416', 'f417', 'f418', 'f419', 'f420', 'f421', 'f422', 'f423', 'f424', 'f425', 'f426', 'f427', 'f428', 'f429', 'f430', 'f431', 'f432', 'f433', 'f434', 'f435', 'f436', 'f437', 'f438', 'f439', 'f440', 'f441', 'f442', 'f443', 'f444', 'f445', 'f446', 'f447', 'f448', 'f449', 'f450', 'f451', 'f452', 'f453', 'f454', 'f455', 'f456', 'f457', 'f458', 'f459', 'f460', 'f461', 'f462', 'f463', 'f464', 'f465', 'f466', 'f467', 'f468', 'f469', 'f470', 'f471', 'f472', 'f473', 'f474', 'f475', 'f476', 'f477', 'f478', 'f479', 'f480', 'f481', 'f482', 'f483', 'f484', 'f485', 'f486', 'f487', 'f488', 'f489', 'f490', 'f491', 'f492', 'f493', 'f494', 'f495', 'f496', 'f497', 'f498', 'f499']
training data did not have the following fields: f499

Comentários muito úteis

O problema ocorre devido a DMatrix..num_col () retornar apenas a quantidade de colunas diferentes de zero em uma matriz esparsa. Portanto, se os dados de treinamento e teste tiverem a mesma quantidade de colunas diferentes de zero, tudo funcionará bem.
Caso contrário, você acabará com listas de nomes de recursos diferentes, porque as funções de validação chamam:

    <strong i="7">@property</strong>
    def feature_names(self):
        """Get feature names (column labels).

        Returns
        -------
        feature_names : list or None
        """
        if self._feature_names is None:
            return ['f{0}'.format(i) for i in range(self.num_col())]
        else:
            return self._feature_names

self._feature_names é Nenhum para matrizes esparsas, e porque self.num_col () retorna apenas a quantidade de colunas diferentes de zero, a validação falha assim que a quantidade de colunas diferentes de zero no campo "a-ser- os dados previstos "diferem da quantidade de colunas diferentes de zero nos dados de treinamento.

Não sei ainda, onde o melhor lugar é consertar isso.

Todos 51 comentários

Parece que isso funciona apenas se as matrizes esparsas forem CSC. Não funciona para matrizes CSR ou COO como nas versões anteriores.

Não é um problema aleatório que ocorre quando as colunas mais à direita são todas 0 ou 1? Talvez o mesmo que # 1091 e # 1221.

@sinhrks : Para mim, isso não é "aleatório". Eu freqüentemente treino o XGBoost em dados altamente esparsos (e é incrível! Ele normalmente supera todos os outros modelos, e por uma margem bem ampla).

Então, depois de colocar o modelo treinado em execução na produção, é claro que vou fazer previsões sobre uma nova parte dos dados recebidos. É muito provável que esses dados sejam esparsos e não tenham um valor para qualquer coluna que seja a última coluna. Então, o XGBoost agora frequentemente falha para mim, e me peguei mudando para outros modelos (menos precisos), simplesmente porque eles têm melhor suporte para dados esparsos.

Alguém sabe exatamente por que esse erro agora surge e como resolvê-lo? Este é um ponto problemático para mim, pois meus scripts existentes estão falhando.

Estou experimentando o xgboost como parte de um pipeline do sklearn e encontrei o mesmo problema. Existe uma solução alternativa até que seja corrigido?

Sim, quando você chamar a previsão, use a função toarray () da matriz esparsa. É terrivelmente ineficiente com a memória, mas funciona com pequenas fatias.

Enviado do meu iPhone

Em 26 de agosto de 2016, às 22h44, Pedro Rodriguez [email protected] escreveu:

Estou experimentando o xgboost como parte de um pipeline do sklearn e encontrei o mesmo problema. Existe uma solução alternativa até que seja corrigido?

-
Você está recebendo isto porque comentou.
Responda a este e-mail diretamente, visualize-o no GitHub ou ignore a conversa.

Por algum motivo, o erro não ocorre se eu salvar e carregar o modelo treinado:

    bst = xgb.train(param, dtrain, num_round)

    # predict is not working without this code
    bst.save_model(model_file_name)
    bst = xgb.Booster(param)
    bst.load_model(model_file_name)

    preds = bst.predict(dtest)

@bryan-woods consegui encontrar uma solução melhor com tocsc . Provavelmente há alguma penalidade de desempenho, mas não tão ruim quanto torná-la uma matriz densa.

Incluindo isso no meu pipeline sklearn logo antes do xgboost funcionar

class CSCTransformer(TransformerMixin):
    def transform(self, X, y=None, **fit_params):
        return X.tocsc()

    def fit_transform(self, X, y=None, **fit_params):
        self.fit(X, y, **fit_params)
        return self.transform(X)

    def fit(self, X, y=None, **fit_params):
        return self

    def get_params(self, deep=True):
        return {}

Nem o formato CSC nem a adição de entradas diferentes de zero na última coluna corrigem o problema na versão mais recente do xgboost. Reverter para a versão 0.4a30 é a única coisa que posso fazer para que funcione, considere o seguinte ajuste (com uma semente reproduzível) no exemplo original:

>>> import xgboost as xgb
>>> import numpy as np
>>> from scipy import sparse
>>> 
>>> np.random.seed(10)
>>> X = sparse.rand(100,10).tocsr()
>>> test = sparse.rand(10, 500).tocsr()
>>> y = np.random.randint(2,size=100)
>>> 
>>> clf = xgb.XGBClassifier()
>>> clf.fit(X,y)
XGBClassifier(base_score=0.5, colsample_bylevel=1, colsample_bytree=1,
       gamma=0, learning_rate=0.1, max_delta_step=0, max_depth=3,
       min_child_weight=1, missing=None, n_estimators=100, nthread=-1,
       objective='binary:logistic', reg_alpha=0, reg_lambda=1,
       scale_pos_weight=1, seed=0, silent=True, subsample=1)
>>> 
>>> try:
...     pred = clf.predict_proba(test)
...     print "Works when csr with version %s" %xgb.__version__
... except ValueError:
...     "Broken when csr with version %s" %xgb.__version__
... 
'Broken when csr with version 0.6'
>>> try:
...     pred = clf.predict_proba(test.tocsc())
...     print "Works when csc with version %s" %xgb.__version__
... except ValueError:
...     "Still broken when csc with version %s" %xgb.__version__
... 
'Still broken when csc with version 0.6'
>>> try:
...     test[0,(test.shape[1]-1)] = 1.0
...     pred = clf.predict_proba(test)
...     print "Works when adding non-zero entries to last column with version %s" %xgb.__version__
... except ValueError:
...     "Still broken when adding non-zero entries to last column with version %s" %xgb.__version__
... 
/home/david.mcgarry/.conda/envs/ml/lib/python2.7/site-packages/scipy/sparse/compressed.py:730: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
  SparseEfficiencyWarning)
'Still broken when adding non-zero entries to last column with version 0.6'
>>> import xgboost as xgb
>>> import numpy as np
>>> from scipy import sparse
>>> 
>>> np.random.seed(10)
>>> X = sparse.rand(100,10).tocsr()
>>> test = sparse.rand(10, 500).tocsr()
>>> y = np.random.randint(2,size=100)
>>> 
>>> clf = xgb.XGBClassifier()
>>> clf.fit(X,y)
XGBClassifier(base_score=0.5, colsample_bylevel=1, colsample_bytree=1,
       gamma=0, learning_rate=0.1, max_delta_step=0, max_depth=3,
       min_child_weight=1, missing=None, n_estimators=100, nthread=-1,
       objective='binary:logistic', reg_alpha=0, reg_lambda=1,
       scale_pos_weight=1, seed=0, silent=True, subsample=1)
>>> 
>>> try:
...     pred = clf.predict_proba(test)
...     print "Works when csr with version %s" %xgb.__version__
... except ValueError:
...     "Broken when csr with version %s" %xgb.__version__
... 
Works when csr with version 0.4
>>> try:
...     pred = clf.predict_proba(test.tocsc())
...     print "Works when csc with version %s" %xgb.__version__
... except ValueError:
...     "Still broken when csc with version %s" %xgb.__version__
... 
Works when csc with version 0.4
>>> try:
...     test[0,(test.shape[1]-1)] = 1.0
...     pred = clf.predict_proba(test)
...     print "Works when adding non-zero entries to last column with version %s" %xgb.__version__
... except ValueError:
...     "Still broken when adding non-zero entries to last column with version %s" %xgb.__version__
... 
/Users/david.mcgarry/anaconda/envs/ml/lib/python2.7/site-packages/scipy/sparse/compressed.py:739: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
  SparseEfficiencyWarning)
Works when adding non-zero entries to last column with version 0.4

Mesmo problema aqui, algo definitivamente quebrou na última versão. Não tive esse problema antes com o mesmo conjunto de dados e processamento. Posso estar errado, mas parece que atualmente não há testes de unidade com matrizes csr esparsas em Python usando a API sklearn. Seria possível adicionar o exemplo @dmcgarry acima a tests/python/tests_with_sklearn.py ?

Tentei contornar isso usando .toarray () com matrizes esparsas CSR, mas algo está seriamente quebrado. Se eu carregar um modelo salvo e tentar usá-lo para fazer previsões com .toarray (), não recebo uma mensagem de erro, mas os resultados estão incorretos. Eu rolei de volta para 0.4a30 e funciona bem. Não tive tempo para descobrir a causa raiz, mas não é bom.

O problema ocorre devido a DMatrix..num_col () retornar apenas a quantidade de colunas diferentes de zero em uma matriz esparsa. Portanto, se os dados de treinamento e teste tiverem a mesma quantidade de colunas diferentes de zero, tudo funcionará bem.
Caso contrário, você acabará com listas de nomes de recursos diferentes, porque as funções de validação chamam:

    <strong i="7">@property</strong>
    def feature_names(self):
        """Get feature names (column labels).

        Returns
        -------
        feature_names : list or None
        """
        if self._feature_names is None:
            return ['f{0}'.format(i) for i in range(self.num_col())]
        else:
            return self._feature_names

self._feature_names é Nenhum para matrizes esparsas, e porque self.num_col () retorna apenas a quantidade de colunas diferentes de zero, a validação falha assim que a quantidade de colunas diferentes de zero no campo "a-ser- os dados previstos "diferem da quantidade de colunas diferentes de zero nos dados de treinamento.

Não sei ainda, onde o melhor lugar é consertar isso.

Também temo que haja um problema fundamental com o manuseio de matrizes esparsas, por causa do que @bryan-woods relatou: Digamos que temos x colunas zero tanto no trem quanto no teste, mas com índices diferentes => Haverá não pode haver erro, porque "feature_names (self)" retorna a mesma lista de recursos para ambos os conjuntos, mas as previsões podem estar erradas, devido à não correspondência de índices de coluna diferentes de zero entre trem e teste.

Alguém trabalhou neste assunto? Alguém tem pelo menos um teste de unidade desenvolvido que possamos usar para desenvolver?

Eu não trabalhei nisso, mas o exemplo de @dmcgarry acima poderia ser usado como um início de um teste de unidade, eu acho,

import xgboost as xgb
import numpy as np
import scipy.sparse


def test_xgbclassifier_sklearn_sparse():
    np.random.seed(10)
    X = scipy.sparse.rand(100,10).tocsr()
    test = scipy.sparse.rand(10, 500).tocsr()
    y = np.random.randint(2,size=100)

    clf = xgb.XGBClassifier()
    clf.fit(X,y)
    pred = clf.predict_proba(test)

Eu criei alguns novos testes de matriz esparsa em minha bifurcação do repo. Para aqueles que estão interessados:
https://github.com/bryan-woods/xgboost/blob/sparse_test/tests/python/test_scipy_sparse.py

Para executar os testes do diretório raiz do checkout:
python -m nose tests / python / test_scipy_sparse.py

Você notará que ambos os testes falham. Isso, pelo menos, fornecerá um teste contra o qual desenvolver.

Também estou tendo esse problema, mas não consigo descobrir qual é a melhor maneira de consertar até que seja finalmente resolvido na biblioteca.

você pode adicionar um recurso à sua lista de recursos com um índice máximo de recursos, como maxid: 0

passar um dataframe resolveu o problema para mim

como posso reverter para a versão 0.4?

pip install --upgrade xgboost == 0.4a30

Todos os tipos de matrizes esparsas não funcionaram para mim (estou trabalhando com dados tf-idf). Tive que reverter para a versão anterior. Obrigado pela dica!

Todos vocês que ainda estão tendo problemas: o código que estão usando inclui as correções em # 1606?

Sim, instalei a última versão do xgboost e ainda estou tendo esse problema.

Isso ainda existe e é facilmente reproduzível. Se você usar um conjunto de dados grande o suficiente, é menos provável que isso ocorra, mas se você estiver envolvendo isso em um objeto de pesquisa de grade, é quase certo que ocorre dentro de uma divisão cv onde os recursos disponíveis nos conjuntos de teste train / cv são diferentes.

Honestamente, eu realmente não entendo por que DMatrix ignora a dica de forma que é fornecida por matrizes esparsas scipy. Ele deve definir o tamanho com base nessas informações, em vez de calculá-lo.

Estou usando a API nativa Xgboost Python (0,6) e recebo o mesmo erro ao carregar uma DMatrix de um arquivo de formato LIBSVM [esparso], se alguma das linhas contém a última coluna definida. Minha solução alternativa foi definir uma coluna fictícia na primeira linha :(

train_fv_file = 'train_fv_eval.svm'
dtrain = xgb.DMatrix(train_fv_file, feature_names=feature_vector_labels, feature_types=feature_vector_types)

Se é tão fácil de reproduzir, alguém se importa em fornecer um exemplo reproduzível? De preferência, sem a camada sklearn (para isolar uma possível causa).

@gabrielspmoreira : Vejo seu ponto sobre o carregamento de um arquivo LIBSVM que tem as últimas colunas completamente esparsas ... Esse método de construção DMatrix se beneficiaria de ter uma dica num_col também.

In [42]: matrix = xgboost.DMatrix(scipy.sparse.csr_matrix([[0, 2, 3, 0], [0, 2, 2, 0], [1, 0, 5, 0], [0, 1, 0, 0]], shape=(4,4)))
In [43]: matrix.num_col()
Out[43]: 3L

Sempre que uma nova DMatrix é criada em uma subamostra de linhas / colunas, existe a possibilidade de que isso aconteça (o número de colunas é reduzido, embora tenhamos dito explicitamente à DMatrix quantas colunas existem). Isso acontece frequentemente para conjuntos de dados menores ou colunas muito esparsas porque é mais provável que um subconjunto seja todo zeros.

Uma vez que isso acontece entre um trem / conjunto de teste, o modelo não pode avaliar o conjunto de teste porque espera um número diferente de recursos e emite um ValueError.

Estou tentando encontrar um teste onde isso funcione / não funcione dentro do xgboost core e do sklearn-wrapper, pois tenho certeza do que está acontecendo, mas não sei onde está acontecendo.

@ l3link : seu código parece estar desatualizado. Aqui está o que eu recebo:

In [2]: import scipy
   ...: import xgboost
   ...: matrix = xgboost.DMatrix(scipy.sparse.csr_matrix([[0, 2, 3, 0], [0, 2, 2, 0], [1, 0, 5, 0], [0, 1, 0, 0]], shape=(4,4)))
   ...: matrix.num_col()
   ...:
Out[2]: 4L

In [3]: matrix._init_from_csr??
Signature: matrix._init_from_csr(csr)
Source:
    def _init_from_csr(self, csr):
        """
        Initialize data from a CSR matrix.
        """
        if len(csr.indices) != len(csr.data):
            raise ValueError('length mismatch: {} vs {}'.format(len(csr.indices), len(csr.data)))
        self.handle = ctypes.c_void_p()
        _check_call(_LIB.XGDMatrixCreateFromCSREx(c_array(ctypes.c_size_t, csr.indptr),
                                                  c_array(ctypes.c_uint, csr.indices),
                                                  c_array(ctypes.c_float, csr.data),
                                                  len(csr.indptr), len(csr.data),
                                                  csr.shape[1],
                                                  ctypes.byref(self.handle)))
File:      c:\anaconda2\lib\site-packages\xgboost-0.6-py2.7.egg\xgboost\core.py
Type:      instancemethod

Huh,

In [64]: xgboost.__version__ Out[64]: '0.6'

Signature: matrix._init_from_csr(csr) Source: def _init_from_csr(self, csr): """ Initialize data from a CSR matrix. """ if len(csr.indices) != len(csr.data): raise ValueError('length mismatch: {} vs {}'.format(len(csr.indices), len(csr.data))) self.handle = ctypes.c_void_p() _check_call(_LIB.XGDMatrixCreateFromCSR(c_array(ctypes.c_ulong, csr.indptr), c_array(ctypes.c_uint, csr.indices), c_array(ctypes.c_float, csr.data), len(csr.indptr), len(csr.data), ctypes.byref(self.handle))) File: ~/anaconda/lib/python2.7/site-packages/xgboost/core.py Type: instancemethod

Parece bizarro que minha versão .6 tenha XGDMatrixCreateFromCSR em vez de instruções XGDMatrixCreateFromCSREx, que não assumem a forma.
É possível que a distribuição osx seja diferente?

Também temo que haja um problema fundamental com o manuseio de matrizes esparsas, por causa do que @bryan-woods relatou: Digamos que temos x colunas zero tanto no trem quanto no teste, mas com índices diferentes => Haverá não pode haver erro, porque "feature_names (self)" retorna a mesma lista de recursos para ambos os conjuntos, mas as previsões podem estar erradas, devido à não correspondência de índices de coluna diferentes de zero entre trem e teste.

Alguém pode responder a esta pergunta? Voltei para a versão 0.4 e agora parece funcionar, mas temo que esteja funcionando corretamente porque ainda estou usando matrizes muito esparsas.

@ l3link não https://github.com/dmlc/xgboost/blob/master/python-package/xgboost/VERSION de hoje foi alterado pela última vez em 29 de julho, e o último pacote pypi https: //pypi.python. org / pypi / xgboost / data de 9 de agosto. Enquanto a correção foi enviada em 23 de setembro # 1606. Verifique o código mais recente do github.

Eu tive esse problema quando usei pandas DataFrame (representação não esparsa).
Eu o converti em numpy ndarray por meio de df.as_matrix() e me livrei do erro.

Eu também me livrei desse erro depois de converter dataframe em array.

Reordenar as colunas no conjunto de teste na mesma ordem do conjunto de trem corrigiu isso para mim.
Usei dataframes do Pandas. Sem isso, usar .as_matrix() estava gerando o mesmo problema.

Eu fiz:

test = test[train.columns]

Tentei a solução @warpuv e funcionou. Meus dados são grandes, não consigo carregá-los na memória para reordenar as colunas.

A conversão de matrizes csr de treinamento / teste em csc funcionou para mim

Xtrain = scipy.sparse.csc_matrix(Xtrain)

A conversão para csc_matrix funciona, testado em 0.6a2 :

    X_train = scipy.sparse.csc_matrix(X_train)
    X_test = scipy.sparse.csc_matrix(X_test)

    xgb_train = xgb.DMatrix(X_train, label=y_train)
    xgb_test = xgb.DMatrix(X_test, label=y_test)
type(X_train) <class 'scipy.sparse.csr.csr_matrix'>
type(X_test) <class 'scipy.sparse.csr.csr_matrix'>
type(X_train) <class 'scipy.sparse.csc.csc_matrix'>
type(X_test) <class 'scipy.sparse.csc.csc_matrix'>
type(xgb_train) <class 'xgboost.core.DMatrix'>
type(xgb_test) <class 'xgboost.core.DMatrix'>

Minha matriz esparsa original é a saída do vetorizador sklearn tf-idf no formato csr_matrix .

Existe alguma correção ainda?

Acabei de criar a versão mais recente (0.7.post3) em python3 e posso confirmar que esse problema ainda existe. Depois de adaptar o exemplo @dmcgarry acima, ainda estou vendo problemas com csr_matrix e csc_matrix .

import xgboost as xgb
import numpy as np
from scipy import sparse

np.random.seed(10)

X_csr = sparse.rand(100, 10).tocsr()
test_csr = sparse.rand(10, 500).tocsr()

X_csc = sparse.rand(100, 10).tocsc()
test_csc = sparse.rand(10, 500).tocsc()

y = np.random.randint(2, size=100)

clf_csr = xgb.XGBClassifier()
clf_csr.fit(X_csr, y)

clf_csc = xgb.XGBClassifier()
clf_csc.fit(X_csc, y)

# Try with csr
try:
    pred = clf_csr.predict_proba(test_csr)
    print("Works when csr with version %s" %xgb.__version__)
except ValueError:
    print("Broken when csr with version %s" %xgb.__version__)

try:
    test_csr[0,(test_csr.shape[1]-1)] = 1.0
    pred = clf_csr.predict_proba(test_csr)
    print("Works when adding non-zero entries to last column with version %s" %xgb.__version__)
except:
    print("Still broken when adding non-zero entries to last column with version %s" %xgb.__version__)

# Try with csc
try:
    pred = clf_csc.predict_proba(test_csc)
    print("Works when csc with version %s" %xgb.__version__)
except ValueError:
    print("Broken when csc with version %s" %xgb.__version__)

try:
    test_csc[0,(test_csc.shape[1]-1)] = 1.0
    pred = clf_csc.predict_proba(test_csc)
    print("Works when adding non-zero entries to last column with version %s" %xgb.__version__)
except:
    print("Still broken when adding non-zero entries to last column with version %s" %xgb.__version__)

O código acima resultou na seguinte saída:

Broken when csr with version 0.7
Still broken when adding non-zero entries to last column with version 0.7
Broken when csc with version 0.7
Still broken when adding non-zero entries to last column with version 0.7

por favor me ajude

Por que este problema foi fechado?

Eu me deparei com esse problema duas vezes recentemente. Para um caso, eu simplesmente altero o dataframe de entrada em array e funciona. Para o segundo, tenho que realinhar os nomes das colunas do dataframe de teste usando test_df = test_df [train_df.columns]. Em ambos os casos, train_df e test_df têm exatamente os mesmos nomes de coluna.

Acho que não entendi seu comentário @CathyQian , esses train_df / test_df esparsos? Além disso, qual versão do xgboost você estava executando quando encontrou esses problemas?

@CathyQian xgboost depende da _ordem_ das colunas e isso não está relacionado a esse problema.

@ewellinger WRT seu exemplo: um modelo treinado em dados com 10 recursos não deve aceitar dados com 500 recursos para predição, portanto, o erro é lançado. Além disso, a criação de DMatrizes de todas as suas matrizes e a inspeção de num_col e num_row produzem os resultados esperados.

O estado atual dos "problemas de dispersão" é:

  • A criação de DMatrix a partir de CSR e seu uso em um modelo devem funcionar corretamente. O problema foi encerrado visto que esse era o assunto deste problema.
  • A criação de DMatrix de CSC produz um objeto com dimensões corretas, mas pode dar resultados incorretos durante o treinamento ou previsão quando as últimas linhas são totalmente esparsas # 2630. Ainda não tive tempo de consertar essa parte adequadamente.
  • Um parâmetro para especificar um número predefinido de colunas ao carregar dados libsvm no DMatrix ainda não foi implementado. Voluntários para contribuir são bem-vindos.

@warpuv funciona para mim, muito obrigado.

Teve o mesmo erro, com matrizes densas. (xgboost v.0.6 do último anaconda.)
Ocorreu um erro quando executei várias regressões em diferentes subconjuntos de recursos da amostra de treinamento.
Criar uma nova instância de modelo a cada vez antes de ajustar uma próxima regressão corrigiu o problema.

  • Um parâmetro para especificar um número predefinido de colunas ao carregar dados libsvm no DMatrix ainda não foi implementado. Voluntários para contribuir são bem-vindos.

A partir de 0.8, isso ainda não existe né?

A criação de DMatrix de CSC produz um objeto com dimensões corretas, mas pode dar resultados incorretos durante o treinamento ou previsão quando as últimas linhas são totalmente esparsas # 2630. Ainda não tive tempo de consertar essa parte adequadamente.

@khotilov # 3553 corrigiu esse problema.

Um parâmetro para especificar um número predefinido de colunas ao carregar dados libsvm no DMatrix ainda não foi implementado. Voluntários para contribuir são bem-vindos.

@MonsieurWave Para este recurso, uma pequena solicitação de pull para dmlc-core deve resolver o problema. Deixe-me dar uma olhada.

@ hcho3 Muito obrigado.

Por enquanto, eu contornarei esse problema deixando a primeira linha do meu libsvm não tão esparsa, ou seja: salvando até as colunas com valor 0.

Esta página foi útil?
0 / 5 - 0 avaliações