【问题标题】:How to get Top 3 or Top N predictions using sklearn's SGDClassifier如何使用 sklearn 的 SGDClassifier 获得 Top 3 或 Top N 预测
【发布时间】:2015-12-04 08:12:42
【问题描述】:
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
from sklearn import linear_model
arr=['dogs cats lions','apple pineapple orange','water fire earth air', 'sodium potassium calcium']
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(arr)
feature_names = vectorizer.get_feature_names()
Y = ['animals', 'fruits', 'elements','chemicals']
T=["eating apple roasted in fire and enjoying fresh air"]
test = vectorizer.transform(T)
clf = linear_model.SGDClassifier(loss='log')
clf.fit(X,Y)
x=clf.predict(test)
#prints: elements

在上面的代码中,<strong>clf.predict()</strong> 只为 list X 中的样本打印 1 个最佳预测。 我对 list X 中特定样本的 前 3 个预测 感兴趣,我知道函数 <strong>predict_proba</strong>/<strong>predict_log_proba</strong> 返回每​​个特征的所有概率的列表列表 Y 中,但它必须先排序,然后与列表 Y 中的特征关联,然后才能获得 前 3 个结果。 有没有直接有效的方法?

【问题讨论】:

  • @user1269942:非常有用的补充!但是,我并不完全理解“真相”变量的功能。能详细点吗?

标签: python scikit-learn multilabel-classification


【解决方案1】:

没有内置函数,但是有什么问题

probs = clf.predict_proba(test)
best_n = np.argsort(probs, axis=1)[-n:]

?

根据其中一条评论的建议,应将[-n:] 更改为[:,-n:]

probs = clf.predict_proba(test)
best_n = np.argsort(probs, axis=1)[:,-n:]

【讨论】:

  • 没有与相应概率相关的名称!
  • clf.classes_ 提供这些。
  • 切片不应该是best_n = np.argsort(probs, axis=1)[:, -n:]吗?
  • 嘿@AndreasMueller,您究竟如何将 clf.classes_ 映射到概率?我是 Python 新手,在过去的 90 分钟里试图弄清楚如何将类的索引映射到实际的类......谢谢!
  • 还有一个问题:使用 best_n 进行切片提供了第 3 佳、第 2 佳、第 1 佳。你怎么能颠倒顺序,所以它是第一个,第二个,然后是第三个?再次感谢!
【解决方案2】:

希望Andreas 能对此有所帮助。当 loss='hinge' 时 predict_probs 不可用。要在 loss='hinge' 时获得前 n 类:

calibrated_clf = CalibratedClassifierCV(clfSDG, cv=3, method='sigmoid')
model = calibrated_clf.fit(train.data, train.label)

probs = model.predict_proba(test_data)
sorted( zip( calibrated_clf.classes_, probs[0] ), key=lambda x:x[1] )[-n:]

不确定 clfSDG.predict 和 calibrated_clf.predict 是否总是预测同一个类。

【讨论】:

  • 鉴于 SGDClassifier 的 log-loss 是 OvR,您也可以按 decision_function 进行排名,无论如何它都不会更糟。使用 CalibratedClassifierCV 可能更好,但与问题正交。我会使用 LogisticRegression(multiclass='multinomial')。
【解决方案3】:

我知道这个问题已经回答了……但我可以再补充一点……

#both preds and truths are same shape m by n (m is number of predictions and n is number of classes)
def top_n_accuracy(preds, truths, n):
    best_n = np.argsort(preds, axis=1)[:,-n:]
    ts = np.argmax(truths, axis=1)
    successes = 0
    for i in range(ts.shape[0]):
      if ts[i] in best_n[i,:]:
        successes += 1
    return float(successes)/ts.shape[0]

它又快又脏,但我觉得它很有用。可以添加自己的错误检查等。

【讨论】:

    【解决方案4】:

    argsort 以升序显示结果,如果您想避免异常循环或混乱,您可以使用一个简单的技巧。

    probs = clf.predict_proba(test)
    best_n = np.argsort(-probs, axis=1)[:, :n]
    

    否定概率将从最小变为最大,因此您可以按降序获取前 n 个结果。

    【讨论】:

      【解决方案5】:

      正如@FredFoo 在How do I get indices of N maximum values in a NumPy array? 中描述的那样,更快的方法是使用argpartition

      较新的 NumPy 版本(1.8 及更高版本)有一个名为 argpartition 的函数 为了这。要获取四个最大元素的索引,请执行

      >>> a = np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
      >>> a array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
      >>> ind = np.argpartition(a, -4)[-4:]
      >>> ind array([1, 5, 8, 0])
      >>> a[ind] array([4, 9, 6, 9])
      

      argsort 不同,此函数在最坏情况下以线性时间运行,但返回的索引不是 已排序,从评估a[ind] 的结果可以看出。如果你 也需要,事后对它们进行排序:

      >>> ind[np.argsort(a[ind])] array([1, 8, 5, 0]) 
      

      以这种方式按排序顺序获取top-k 元素需要O(n + k log k) 时间。

      【讨论】:

        【解决方案6】:

        我编写了一个函数,它输出一个包含前 n 个预测及其概率的数据帧,并将其与类名联系起来。希望这会有所帮助!

        def return_top_n_pred_prob_df(n, model, X_test, column_name):
          predictions = model.predict_proba(X_test)
          preds_idx = np.argsort(-predictions) 
          classes = pd.DataFrame(model.classes_, columns=['class_name'])
          classes.reset_index(inplace=True)
          top_n_preds = pd.DataFrame()
          for i in range(n):
                top_n_preds[column_name + '_prediction_{}_num'.format(i)] =     [preds_idx[doc][i] for doc in range(len(X_test))]
            top_n_preds[column_name + '_prediction_{}_probability'.format(i)] = [predictions[doc][preds_idx[doc][i]] for doc in range(len(X_test))]
            top_n_preds = top_n_preds.merge(classes, how='left', left_on= column_name + '_prediction_{}_num'.format(i), right_on='index')
            top_n_preds = top_n_preds.rename(columns={'class_name': column_name + '_prediction_{}'.format(i)})
            try: top_n_preds.drop(columns=['index', column_name + '_prediction_{}_num'.format(i)], inplace=True) 
            except: pass
          return top_n_preds
        

        【讨论】:

          猜你喜欢
          • 2019-03-12
          • 2019-07-18
          • 2019-03-08
          • 2011-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-06
          相关资源
          最近更新 更多