简体   繁体   中英

TypeError: A sparse matrix was passed, but dense data is required (multilabel K nearest neighbours)

I'm having trouble with fitting an instance of an MLkNN model (from scikit-multilearn) after doing GridSearchCV (from scikit-learn). I am getting an error. Here is the appropriate code:

#From MachineLearningMastery: https://machinelearningmastery.com/multivariate-time-series-forecasting-lstms-keras/

def series_to_supervised(n_lags, n_vars, data, n_out=1, dropnan=True):
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()

    #input sequence t-n, ..., t-1
    for i in range(n_lags, 0, -1): #for i in 3 to 0 not including 0
        cols.append(df.shift(i))
        names += [('var%d(t-%d)' % (j+1, i)) for j in range (n_vars)]

    #forecast sequence t, t+1, ..., t+n
    for i in range(0, n_out):
        cols.append(df.shift(-i))
        if i==0:
            names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
        else:
            names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]

    agg = concat(cols, axis=1)
    agg.columns = names
    if dropnan:
        agg.dropna(inplace=True)

    return agg

def testexamples():

    def average_precision_wrapper(estimator, X, y):
        if X.ndim == 2:
            X = X.reshape((-1)) #[1, 1497] becomes [1497,], needed for average_precision
        if y.ndim == 2:
            y = y.reshape((-1)) #[1, 1497] ... as above
        y_pred = estimator.predict(X).toarray()
        return average_precision_score(y, y_pred)

    true_values = np.random.choice([0,1], size=(500, 1497), p=[0.99, 0.01])

    #Need to convert this to supervised learning. Use previous 2 days to predict (lag=2)
    n_lags = 2
    n_vars = true_values.shape[1]
    all_data = np.asarray(series_to_supervised(n_lags, n_vars, data=true_values))

    train_x = all_data[:400, :int(n_vars*n_lags)] 
    train_y = all_data[:400, int(n_vars*n_lags):] 

    test_x = all_data[-100:, :int(n_vars*n_lags)]
    test_y = all_data[-100:, int(n_vars*n_lags):]

    parameters = {'k': range(1,5), 's': [0.5, 0.75, 1]}
    checked_model = GridSearchCV(MLkNN(), parameters, scoring='average_precision')
    print('type: train_x: ', type(train_x), ' type: train_y: ', type(train_y))
    checked_model.fit(train_x, train_y)

Full trace:

user@GPU8:~/path/to/dir$ python May15_mlknn.py 
    type: train_x:  <type 'numpy.ndarray'>  type: train_y:  <type 'numpy.ndarray'>

Traceback (most recent call last):
  File "May15_mlknn.py", line 380, in <module>
    testexamples()
  File "May15_mlknn.py", line 340, in testexamples
    checked_model.fit(train_x, train_y)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/model_selection/_search.py", line 945, in fit
    return self._fit(X, y, groups, ParameterGrid(self.param_grid))
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/model_selection/_search.py", line 564, in _fit
    for parameters in parameter_iterable
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 758, in __call__
    while self.dispatch_one_batch(iterator):
  File "user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 608, in dispatch_one_batch
    self._dispatch(tasks)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 571, in _dispatch
    job = self._backend.apply_async(batch, callback=cb)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/_parallel_backends.py", line 109, in apply_async
    result = ImmediateResult(func)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/_parallel_backends.py", line 326, in __init__
    self.results = batch()
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 131, in __call__
    return [func(*args, **kwargs) for func, args, kwargs in self.items]
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/model_selection/_validation.py", line 260, in _fit_and_score
    test_score = _score(estimator, X_test, y_test, scorer)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/model_selection/_validation.py", line 288, in _score
    score = scorer(estimator, X_test, y_test)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/metrics/scorer.py", line 196, in __call__
    return self._sign * self._score_func(y, y_pred, **self._kwargs)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/metrics/ranking.py", line 184, in average_precision_score
    average, sample_weight=sample_weight)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/metrics/base.py", line 88, in _average_binary_score
    y_score = check_array(y_score)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/utils/validation.py", line 380, in check_array
    force_all_finite)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/utils/validation.py", line 243, in _ensure_sparse_format
    raise TypeError('A sparse matrix was passed, but dense '
TypeError: A sparse matrix was passed, but dense data is required. Use X.toarray() to convert to a dense numpy array.

I have already seen this and this and this . My question is different because I checked the types of train_x and train_y, and both are dense numpy arrays.

What am I doing wrong and how can I fix it?

EDIT:

I'm now trying the answer provided below, but with a modification due to the error I got (answer here ):

def average_precision_wrapper(estimator, X, y):
    if X.ndim == 2:
        X = X.reshape((-1)) #(1, 1497) becomes (1497,), needed for average_precision
    if y.ndim == 2:
        y = y.reshape((-1)) #(1, 1497) ... as above
    y_pred = estimator.predict(X).toarray()
    return average_precision_score(y, y_pred)

EDIT 2: That was no good after all. I get ValueError: query data dimension must match training data dimension . Here's the trace:

/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/utils/validation.py:395: DeprecationWarning: Passing 1d arrays as data is deprecated in 0.17 and will raise ValueError in 0.19. Reshape your data either using X.reshape(-1, 1) if your data has a single feature or X.reshape(1, -1) if it contains a single sample.
  DeprecationWarning)
Traceback (most recent call last):
  File "May15_mlknn_to_so.py", line 393, in <module>
    testexamples()
  File "May15_mlknn_to_so.py", line 353, in testexamples
    checked_model.fit(train_x, train_y)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/model_selection/_search.py", line 945, in fit
    return self._fit(X, y, groups, ParameterGrid(self.param_grid))
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/model_selection/_search.py", line 564, in _fit
    for parameters in parameter_iterable
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 758, in __call__
    while self.dispatch_one_batch(iterator):
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 608, in dispatch_one_batch
    self._dispatch(tasks)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 571, in _dispatch
    job = self._backend.apply_async(batch, callback=cb)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/_parallel_backends.py", line 109, in apply_async
    result = ImmediateResult(func)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/_parallel_backends.py", line 326, in __init__
    self.results = batch()
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 131, in __call__
    return [func(*args, **kwargs) for func, args, kwargs in self.items]
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/model_selection/_validation.py", line 260, in _fit_and_score
    test_score = _score(estimator, X_test, y_test, scorer)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/model_selection/_validation.py", line 288, in _score
    score = scorer(estimator, X_test, y_test)
  File "May15_mlknn_to_so.py", line 307, in average_precision_wrapper
    y_pred = estimator.predict(X).toarray()
  File "May15_mlknn_to_so.py", line 237, in predict
    self.knn_.kneighbors(X, self.k + self.ignore_first_neighbours, return_distance=False)]
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/neighbors/base.py", line 381, in kneighbors
    for s in gen_even_slices(X.shape[0], n_jobs)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 758, in __call__
    while self.dispatch_one_batch(iterator):
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 608, in dispatch_one_batch
    self._dispatch(tasks)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 571, in _dispatch
    job = self._backend.apply_async(batch, callback=cb)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/_parallel_backends.py", line 109, in apply_async
    result = ImmediateResult(func)
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/_parallel_backends.py", line 326, in __init__
    self.results = batch()
  File "/user/pkgs/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.py", line 131, in __call__
    return [func(*args, **kwargs) for func, args, kwargs in self.items]
  File "sklearn/neighbors/binary_tree.pxi", line 1294, in sklearn.neighbors.kd_tree.BinaryTree.query (sklearn/neighbors/kd_tree.c:11337)
ValueError: query data dimension must match training data dimension

The MLkNN.predict method returns a scipy.sparse array. The scorer 'average_precision' expects a numpy array. You can write a small wrapper that makes this conversion yourself:

from sklearn.model_selection import GridSearchCV
from skmultilearn.adapt import MLkNN
from sklearn.metrics import average_precision_score

def average_precision_wrapper(estimator, X, y):
    y_pred = estimator.predict(X).toarray()
    return average_precision_score(y, y_pred)

# Make dummy features of shape (100,5)
train_x = np.random.random((100,5))
# Make dummy one-hot encoded labels of shape (100,4)
train_y = np.zeros((100,4), dtype=int)
for i in range(100):
    train_y[i, i%4] = 1

parameters = {'k': range(1,5), 's': [0.5, 0.75, 1]}
checked_model = GridSearchCV(MLkNN(), parameters, scoring=average_precision_wrapper)
checked_model.fit(train_x, train_y)

Solved, with help from user2653663: I changed the metric to the Hamming loss, but had to create a scorer to do that using make_scorer from sklearn.metrics.

parameters = {'k': range(1,5), 's': [0.5, 0.75, 1]}
#checked_model = GridSearchCV(MLkNN(), parameters, scoring='f1_samples')
start = time.time()
#checked_model = GridSearchCV(MLkNN(), parameters, scoring='average_precision')
hloss_scorer = make_scorer(hamming_loss, greater_is_better=False)
checked_model = GridSearchCV(MLkNN(), parameters, scoring=hloss_scorer)


checked_model.fit(train_x, train_y)
end = time.time()
print('best parameters: ', checked_model.best_params_, 'best Hamming loss: ', checked_model.best_score_)

best_model = MLkNN(k=checked_model.best_params_['k'], s=checked_model.best_params_['s'])
best_model.fit(train_x, train_y)
pred_values = best_model.predict(test_x) #returns 0/1 classes, not probabilities
pred_values = np.array(pred_values.todense())

true_values = test_y

#Metrics

bincross = []
ap = []
ap_weighted = []
h_loss = []

for i in range(1, pred_values.shape[0]):
    true_vals = true_values[i,:]
    pred_vals = pred_values[i,:]
    pred_vals = np.squeeze(pred_vals)
    h_loss.append(hamming_loss(true_vals, pred_vals))

print("***********************")
print("MLKNN with k=best")
print("***********************")

print("Hamming loss: ", h_loss)

h_loss = np.asarray(h_loss)

print("total Hamming loss: ", np.sum(h_loss))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM