fengdu78 / lihang-code Goto Github PK
View Code? Open in Web Editor NEW《统计学习方法》的代码实现
《统计学习方法》的代码实现
sklearn库没有后剪枝操作,粗略看了下您的代码发现也没有,希望能加上借鉴一下。自己写的代码质量有点垃圾
有个问题想问下。我看您的代码还有文档内容和别人写的一模一样。所以您这个项目最多只是一个整理集合吧。有自己的内容吗?
很奇怪,把下载的jupyter notebook直接运行(在vscode上,所有代码都执行了),分类成功率只有0.5左右,python版本为3.7.2。我把曲线画出来,基本就是 所有点都划分为一类了。 请问,能判断一下原因吗?
您好,我直接运行svm代码,输出的score很低,只有0.5,而且多次运行存在score还不同,大部分结果都是很低
在研读第10章隐形马尔可夫模型代码的时候,发现出现两个问题:
1.注释错误:
代码中的:N = len(Q) # 状态序列的大小
由定义可知Q应是所有可能状态的集合,而不是状态序列,状态序列为I
因此应更改为:N = len(Q) #可能存在的状态数量
以免误解
2.维特比算法实现中的错误:
在维特比算法实现的过程中多次用到argmax函数,由于其返回的是索引,因此应+1才能和正常的下标值相符合。原代码中在计算时未+1,但在输出时却加了1,导致算法计算的delta、psis参数部分正确、部分错误,最终预测的状态序列也是错误的。
原代码
psis[i][t] = np.argmax(np.multiply([delta[t-1] for delta in deltas], [a[i] for a in A])) #未+1
...
I[0][M-1] = np.argmax([delta[M-1] for delta in deltas]) #未+1
print('i%d=argmax[deltaT(i)]=%d' % (M, I[0][M-1]+1)) #输出时手动+1
for t in range(M-2, -1, -1):
I[0][t] = psis[int(I[0][t+1])][t+1] #因之前未+1,因此此处直接当索引使用了
print('i%d=psis%d(i%d)=%d' % (t+1, t+2, t+2, I[0][t]+1)) #输出时手动+1
print(I) #最终输出错误
建议在计算产生索引时统一+1,以生成符合实际的下标值;而在使用索引时再-1来避免超限
更改代码:
psis[i][t] = np.argmax(np.multiply([delta[t-1] for delta in deltas], [a[i] for a in A])) + 1 #索引值要+1
...
I[0][M-1] = np.argmax([delta[M-1] for delta in deltas]) + 1 #索引值要+1
print('i%d=argmax[deltaT(i)]=%d' % (M, I[0][M-1])) #直接输出
for t in range(M-2, -1, -1):
I[0][t] = psis[int(I[0][t+1]) - 1][t+1] #用做索引,因此-1
print('i%d=psis%d(i%d)=%d' % (t+1, t+2, t+2, I[0][t])) #直接输出
print("状态序列I:", I)
此时所有参数及最终结果均正确,且与书本中的结果一致。
def residuals_func_regularization(p, x, y): ret = fit_func(p, x) - y ret = np.append(ret, np.sqrt(0.5*regularization*np.square(p))) # L2范数作为正则化项 return ret
是不是应该改成
def residual_func_regularization(p, x, y): ret = fit_function(p, x) - y ret = np.append(ret / np.sqrt(p.size), np.sqrt(0.5 * regularization * np.square(p))) return ret
L2 范数 前面的是不是要处以N
self.alpha[i1] = alpha1_new
self.alpha[i2] = alpha2_new
self.b = b_new
self.E[i1] = self._E(i1)
self.E[i2] = self._E(i2)
想请教一下这边b更新后,除了index为i1和i2的其他的Ei为什么不需要更新。
谢谢。
文档路径:lihang-code/第02章 感知机/2.Perceptron.ipynb
“随即梯度下降法 Stochastic Gradient Descent”
随即应该是随机吧?
请问为什么clf = Perceptron(fit_intercept=False, max_iter=1000, shuffle=False)这里的fit_intercept要设置为false呢,这样不就没有截距了吗
对eta有如下代码限制:
if eta <= 0:
# print('eta <= 0')
continue
不是很明白为什么限制<0,改成==0后也能正常运行,跑出过一两次0.9+
但由于大多数情况下score评分接近0.5,所以也不知道是否真的正确
第一题极大似然估计的算法描述是否有错误?个人认为应当改为arg max L(p)
A.data /= rsums[ri]
这句话好像不太对
因为A.data返回的顺序并不是按行的顺序展开的
这就导致了错位的情况
手动实现向量化的norm,应该通用性更好一些, 是否可行,请指正:
def predict_leon(self, X):
dist = np.power(X - self.X_train, self.p).sum(axis=1)
dist = np.power(dist, 1 / self.p)
knn = self.y_train[np.argsort(dist)[:self.n]]
# 统计
count_pairs = Counter(knn)
max_count = sorted(count_pairs.items(), key=lambda x: x[1])[-1][0]
return max_count
not sqaure
AdaBoost类中的_G函数,direct变量很明显一直在变,返回的是最后一个划分得到的direct
numpy.linalg.svd(A) 中, 如果用多元随机变量的协方差的无偏样本对协方差矩阵C= Cov(X^T,X) = X^T*X/(n-1) 进行 SVD, A应该是中心化的X, 即
所以, 应该用 np.linalg.svd(X), 其中 X 做了中心化。实例中做标准化再 SVD 是用相关系数矩阵为标准做PCA。
相关资源参考: PCA 和 SVD 关系
您好,我在执行您下面这段代码时觉得有点困惑
`def predict(self, X):
# 取出n个点
knn_list = []
for i in range(self.n):
dist = np.linalg.norm(X - self.X_train[i], ord=self.p)
knn_list.append((dist, self.y_train[i]))
for i in range(self.n, len(self.X_train)):
max_index = knn_list.index(max(knn_list, key=lambda x: x[0]))
dist = np.linalg.norm(X - self.X_train[i], ord=self.p)
if knn_list[max_index][0] > dist:
knn_list[max_index] = (dist, self.y_train[i])
# 统计
knn = [k[-1] for k in knn_list]
count_pairs = Counter(knn)
max_count = sorted(count_pairs, key=lambda x:x)[-1]
return max_count`
在max_count这一行,对count_pairs进行排序然后选择最大的那个作为标签;
您这边的key是不是有点问题,直接对dict排序会对键排序吧,这样如何能选择到value最大的呢?
我是这样写的max_count = sorted(count_pairs.items(), key=lambda x: x[1])[-1][0]
,不知道我理解的对不对
第3章k近邻法中In[10]第34行的n=10,这句话有用到吗?
The following code that creat a pdf:
tree_pic = export_graphviz(clf, out_file="mytree.pdf")
with open('mytree.pdf') as f:
dot_graph = f.read()
However, I can not open that, I wonder is there anything wrong?
def fiitting(M=0),这个函数,返回值应该是return p_lsq[0]
因为leastsq的返回值是一个tuple,它里面有多个元素,第一个元素是(参数)的求解结果,所以返回值应该是p_lsq[0]???
https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.leastsq.html
您好,在此函数统计阶段,最后排序是对yi的标签出现的次数排序,但是单独拿出来代码好像是对yi标签的排序。求解答
def pmf(i, pro_A, pro_B, por_C):
pro_1 = pro_A * math.pow(pro_B, data[i]) * math.pow(
(1 - pro_B), 1 - data[i])
pro_2 = pro_A* math.pow(pro_C, data[i]) * math.pow(
(1 - pro_C), 1 - data[i])
return pro_1 / (pro_1 + pro_2)
第四行是不是应该改成
pro_2 = (1-pro_A)* math.pow(pro_C, data[i]) * math.pow(
(1 - pro_C), 1 - data[i])
比如一个观测序列长度为400,观测序列的取值为[1,2,...,20],状态序列取值为[1,2,...,8]时,把这样的数据扔到HMM模型里面,得到的边际概率基本都为零
在第8章提升方法中,进行了二分类AdaBoost的实现,其中在G(x)函数中,根据当前阈值v得到的error与现有error的比较来决定是否更新最小误差error、分类器输出compare_array以及最好的阈值best_v,但是却没有对弱分类器的类型direct(“positive”或“nagetive”)进行更新。
原代码:
if weight_error < error:
error = weight_error
compare_array = _compare_array
best_v = v
return best_v, direct, error, compare_array
修正代码:
f_direct = "positive" #定义f_direct,为最终的direct
...
...
...
if weight_error < error:
error = weight_error
compare_array = _compare_array
best_v = v
f_direct = direct #对f_direct进行更新
return best_v, f_direct, error, compare_array
# update P(w|z)
for zi in range(self.K):
sum2 = np.zeros((n_w))
for wi in range(n_w):
for di in range(n_d):
sum2[wi] = sum2[wi] + X[di, wi] * p_z_dw[di, wi, zi]
sum1 = np.sum(sum2)
if sum1 == 0:
sum1 = 1
for wi in range(n_w):
p_w_z[zi, wi] = sum2[wi] / sum1
是不是应改为
# update P(w|z)
for zi in range(self.K):
sum2 = np.zeros((n_w))
for wi in range(n_w):
for di in range(n_d):
sum2[wi] = sum2[wi] + X[di, wi] * p_z_dw[di, wi, zi]
sum1 = np.sum(sum2)
if sum1 == 0:
sum1 = 1
for wi in range(n_w):
p_w_z[zi, wi] = sum2[wi] / sum1
def fitting(M=0):
"""
:param M:多项式的次数
:return:
"""
for d in range(len(X_train)): X = X_train[d] y = y_train[d] if y * self.sign(X, self.w, self.b) <= 0: self.w = self.w + self.l_rate*np.dot(y, X) self.b = self.b + self.l_rate*y wrong_count += 1 if wrong_count == 0: is_wrong = True
这样写是梯度下降,应该不是随机梯度下降,以下是修改后的随机梯度下降,请参考,如有误,还请指出:
for d in range(len(X_train)): x = X_train[d] y = y_train[d] if y * self.sign(x, self.w, self.b) <= 0: wrong_index_list.append(d) if len(wrong_index_list) == 0: break else: index = random.randint(0, len(wrong_index_list) - 1) w_index = wrong_index_list[index] self.w = self.w + self.l_rate*np.dot(y_train[w_index], X_train[w_index]) self.b = self.b + self.l_rate*y_train[w_index]
The code for the KD tree seems to have an issue, as it only searches for leaf nodes without any fallback steps
您好,我对贝叶斯算法实现中的先验概率有些疑惑
`
def calculate_probabilities(self, input_data):
# summaries:{0.0: [(5.0, 0.37),(3.42, 0.40)], 1.0: [(5.8, 0.449),(2.7, 0.27)]}
# input_data:[1.1, 2.2]
probabilities = {}
for label, value in self.model.items():
probabilities[label] = 1 #probability[label]=1???
for i in range(len(value)):
mean, stdev = value[i]
probabilities[label] *= self.gaussian_probability(input_data[i], mean, stdev)
return probabilities
`
为什么这里的probabilities[label]可以直接赋值为1呢,这样所有的类的先验概率是不是都一样了,为什么不根据样本计算这里的probabilities[label]呢
谢谢解答
在_G函数中
关于direct的保存,不能保证最终返回的direct 是错误最低的direct
你好,作者,请问下第一张关于L2 reg的代码,您为什么使用的是L2: 0.5 * regularization * np.square(p)
而没有对平方求和?望得到您的答复,此致!
训练后,alpha参数没更新,还是全1
def _G(self, features, labels, weights):
...
if weight_error_positive < weight_error_nagetive:
weight_error = weight_error_positive
_compare_array = compare_array_positive
direct = 'positive' 修改为 _direct = 'positive'
else:
weight_error = weight_error_nagetive
_compare_array = compare_array_nagetive
direct = 'nagetive' 修改为 _direct = 'positive'
# print('v:{} error:{}'.format(v, weight_error))
if weight_error < error:
error = weight_error
compare_array = _compare_array
best_v = v
加上 direct = _direct
就是direct也得像误差一样处理吧?否则后续非最优阈值对应的direct也可能改变已得结果
话说当我将你的.ipynb中代码写成.py文件时,发现代码中变量的作用域很是不规范,不知道是不是我个人习惯的原因
alpha2_new_unc = self.alpha[i2] + self.Y[i2] * (E2 - E1) / eta
这边应该是E1- E2 吧
def init(self, k=1):
self.k = k
self.kdtree = None
# 构建kd tree
def _fit(self, X, depth=0):
try:
k = self.k
except IndexError as e:
return None
# 这里可以展开,通过方差选择axis
axis = depth % k
维度k取1,坐标轴始终是零!
应该是 LogisticRegressionClassifier
函数 pmf中的变量名称和函数中使用的不一致。
第五章,在分类决策树的train()
函数里
sub_train_df = train_data.loc[train_data[max_feature_name] ==
f].drop([max_feature_name], axis=1)
这里把当前最大特征那一行给drop掉了,导致下面通过index索引特征时会出现错误
# class Node
def predict(self, features):
if self.root is True:
return self.label
return self.tree[features[self.feature]].predict(features)
建议可以直接把DTree类中的predict()
函数的参数改成Dataframe格式,这样不再需要通过当先特征的下标来索引,而是直接通过特征来索引
# class DTree
def predict(self, X):
m,n = np.shape(X)
pred_res = []
for i in range(m):
temp = X.iloc[i,:]
pred_res.append(self.tree.predict(temp))
return pred_res
# class Node
def predict(self, test):
if self.root is True:
return self.label
return self.tree[test[self.feature_name]].predict(test)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.