Scikit-learn 多目标
Scikit-learn multiple targets
我离开这个 example 使用 scikit-learn 创建分类器图像。
虽然每张图片属于一个类别一切正常,但每张图片可能属于多个类别,例如:白天有狗的照片、晚上有猫的照片、晚上有猫和狗的照片等...
我写道:
target=[[0,1],[0,2],[1,2],[0,2,3]]
target = MultiLabelBinarizer().fit_transform(target)
classifier = svm.SVC(gamma=0.001)
classifier.fit(data, target)
但是我得到这个错误:
Traceback (most recent call last):
File "test.py", line 49, in <module>
classifier.fit(data, target)
File "/home/mezzo/.local/lib/python2.7/site-packages/sklearn/svm/base.py", line 151, in fit
y = self._validate_targets(y)
File "/home/mezzo/.local/lib/python2.7/site-packages/sklearn/svm/base.py", line 514, in _validate_targets
y_ = column_or_1d(y, warn=True)
File "/home/mezzo/.local/lib/python2.7/site-packages/sklearn/utils/validation.py", line 551, in column_or_1d
raise ValueError("bad input shape {0}".format(shape))
ValueError: bad input shape (4, 4)
完整代码
import numpy as np
import PIL
from PIL import Image
import matplotlib.image as mpimg
# The digits dataset
digits = datasets.load_digits()
def normalize(old_im):
base = 400
if (old_im.size[0] > old_im.size[1]):
wpercent = (base/float(old_im.size[0]))
hsize = int((float(old_im.size[1])*float(wpercent)))
old_im = old_im.resize((base,hsize), PIL.Image.ANTIALIAS)
else:
wpercent = (base/float(old_im.size[1]))
wsize = int((float(old_im.size[0])*float(wpercent)))
old_im = old_im.resize((wsize, base), PIL.Image.ANTIALIAS)
old_size = old_im.size
new_size = (base, base)
new_im = Image.new("RGB", new_size)
new_im.paste(old_im, ((new_size[0]-old_size[0])/2,
(new_size[1]-old_size[1])/2))
#new_im.show()
new_im.save('prov.jpg')
return mpimg.imread('prov.jpg')
# To apply a classifier on this data, we need to flatten the image, to
# turn the data in a (samples, feature) matrix:
imgs = np.array([normalize(Image.open('/home/mezzo/Immagini/1.jpg')),normalize(Image.open('/home/mezzo/Immagini/2.jpg')),normalize(Image.open('/home/mezzo/Immagini/3.jpg')),normalize(Image.open('/home/mezzo/Immagini/4.jpg'))])
n_samples = len(imgs)
data = imgs.reshape((n_samples, -1))
target=[[0,1],[0,2],[1,2],[0,2,3]]
target = MultiLabelBinarizer().fit_transform(target)
# Create a classifier: a support vector classifier
classifier = svm.SVC(gamma=0.001)
# We learn the digits on the first half of the digits
classifier.fit(data, target)
# Now predict the value of the digit on the second half:
predicted = classifier.predict(data)
print("Classification report for classifier %s:\n%s\n"
% (classifier, metrics.classification_report(target, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(target, predicted))
Scikit-learn 的 SVM 实现本身不支持多标签 classification,although it has various other classifiers that do:
- Support multilabel: Decision Trees, Random Forests, Nearest Neighbors, Ridge Regression.
也可以通过将每个唯一的标签组合视为单独的 class 来使用 SVM 进行多标签 class 化。您可以简单地用单个整数标签 which can be done efficiently using np.unique
:
替换 target
矩阵中的每个唯一行
d = np.dtype((np.void, target.dtype.itemsize * target.shape[1]))
_, ulabels = np.unique(np.ascontiguousarray(target).view(d), return_inverse=True)
然后您可以像处理单标签 class化问题一样训练 SVM:
clf = svm.SVC()
clf.fit(data, ulabels)
一个潜在的警告是,如果您没有大量的训练示例,您的 classifier 对于罕见的标签组合的性能可能很差。
发生这种情况是因为您的目标是:
array([[1, 1, 0, 0],
[1, 0, 1, 0],
[0, 1, 1, 0],
[1, 0, 1, 1]])
您的目标必须是形状 (m,),其中 m 是示例数。
处理这个问题的一种方法是将二进制数组转换为标签,如下所示:
for item in target:
print(sum(1<<i for i, b in enumerate(item) if b))
这个输出将是:
3
5
6
13
现在您可以使用 [3,5,6,13]
作为目标。
我离开这个 example 使用 scikit-learn 创建分类器图像。
虽然每张图片属于一个类别一切正常,但每张图片可能属于多个类别,例如:白天有狗的照片、晚上有猫的照片、晚上有猫和狗的照片等... 我写道:
target=[[0,1],[0,2],[1,2],[0,2,3]]
target = MultiLabelBinarizer().fit_transform(target)
classifier = svm.SVC(gamma=0.001)
classifier.fit(data, target)
但是我得到这个错误:
Traceback (most recent call last):
File "test.py", line 49, in <module>
classifier.fit(data, target)
File "/home/mezzo/.local/lib/python2.7/site-packages/sklearn/svm/base.py", line 151, in fit
y = self._validate_targets(y)
File "/home/mezzo/.local/lib/python2.7/site-packages/sklearn/svm/base.py", line 514, in _validate_targets
y_ = column_or_1d(y, warn=True)
File "/home/mezzo/.local/lib/python2.7/site-packages/sklearn/utils/validation.py", line 551, in column_or_1d
raise ValueError("bad input shape {0}".format(shape))
ValueError: bad input shape (4, 4)
完整代码
import numpy as np
import PIL
from PIL import Image
import matplotlib.image as mpimg
# The digits dataset
digits = datasets.load_digits()
def normalize(old_im):
base = 400
if (old_im.size[0] > old_im.size[1]):
wpercent = (base/float(old_im.size[0]))
hsize = int((float(old_im.size[1])*float(wpercent)))
old_im = old_im.resize((base,hsize), PIL.Image.ANTIALIAS)
else:
wpercent = (base/float(old_im.size[1]))
wsize = int((float(old_im.size[0])*float(wpercent)))
old_im = old_im.resize((wsize, base), PIL.Image.ANTIALIAS)
old_size = old_im.size
new_size = (base, base)
new_im = Image.new("RGB", new_size)
new_im.paste(old_im, ((new_size[0]-old_size[0])/2,
(new_size[1]-old_size[1])/2))
#new_im.show()
new_im.save('prov.jpg')
return mpimg.imread('prov.jpg')
# To apply a classifier on this data, we need to flatten the image, to
# turn the data in a (samples, feature) matrix:
imgs = np.array([normalize(Image.open('/home/mezzo/Immagini/1.jpg')),normalize(Image.open('/home/mezzo/Immagini/2.jpg')),normalize(Image.open('/home/mezzo/Immagini/3.jpg')),normalize(Image.open('/home/mezzo/Immagini/4.jpg'))])
n_samples = len(imgs)
data = imgs.reshape((n_samples, -1))
target=[[0,1],[0,2],[1,2],[0,2,3]]
target = MultiLabelBinarizer().fit_transform(target)
# Create a classifier: a support vector classifier
classifier = svm.SVC(gamma=0.001)
# We learn the digits on the first half of the digits
classifier.fit(data, target)
# Now predict the value of the digit on the second half:
predicted = classifier.predict(data)
print("Classification report for classifier %s:\n%s\n"
% (classifier, metrics.classification_report(target, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(target, predicted))
Scikit-learn 的 SVM 实现本身不支持多标签 classification,although it has various other classifiers that do:
- Support multilabel: Decision Trees, Random Forests, Nearest Neighbors, Ridge Regression.
也可以通过将每个唯一的标签组合视为单独的 class 来使用 SVM 进行多标签 class 化。您可以简单地用单个整数标签 which can be done efficiently using np.unique
:
target
矩阵中的每个唯一行
d = np.dtype((np.void, target.dtype.itemsize * target.shape[1]))
_, ulabels = np.unique(np.ascontiguousarray(target).view(d), return_inverse=True)
然后您可以像处理单标签 class化问题一样训练 SVM:
clf = svm.SVC()
clf.fit(data, ulabels)
一个潜在的警告是,如果您没有大量的训练示例,您的 classifier 对于罕见的标签组合的性能可能很差。
发生这种情况是因为您的目标是:
array([[1, 1, 0, 0],
[1, 0, 1, 0],
[0, 1, 1, 0],
[1, 0, 1, 1]])
您的目标必须是形状 (m,),其中 m 是示例数。 处理这个问题的一种方法是将二进制数组转换为标签,如下所示:
for item in target:
print(sum(1<<i for i, b in enumerate(item) if b))
这个输出将是:
3
5
6
13
现在您可以使用 [3,5,6,13]
作为目标。