日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(八)

發(fā)布時間:2024/1/17 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(八) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

上一節(jié)講了決策樹算法,雖然存在一些局限性,但是正是這種局限性造就了集成學(xué)習(xí)中的隨機(jī)森林算法。?


八、集成學(xué)習(xí)與隨機(jī)森林

??假設(shè)要解決一個復(fù)雜的問題,讓眾多學(xué)生去回答,然后匯總他們的答案。在許多情況下,會發(fā)現(xiàn)這個匯總的答案比一個老師的答案要好。同樣,如果匯總了一組預(yù)測變量(例如分類器或回歸因子)的預(yù)測結(jié)果,則通常會得到比最佳個體預(yù)測變量得到更好的預(yù)測結(jié)果。這種技術(shù)被稱為集成學(xué)習(xí)(Ensemble Learning)。?


1、投票分類器(Voting Classifiers)

??創(chuàng)建集成分類器的一個非常簡單的方法是聚合多個分類器(如Linear,Logistic,SVM,k-近鄰、Ramdom forest等)的預(yù)測結(jié)果并預(yù)測得到最多選票的類。這個多數(shù)投票分類器被稱為硬投票(hard voting)分類器。

??

??這個投票分類器通常比集合中最好的分類器實現(xiàn)更高的準(zhǔn)確性。事實上,即使每個分類器是一個弱學(xué)習(xí)器(weak learner)(意味著它只比隨機(jī)猜測略好一點),但如果有足夠的數(shù)量,集合仍然是一個強(qiáng)大的學(xué)習(xí)器(達(dá)到高精度)。比如每個學(xué)習(xí)器能到達(dá)51%的精度,1000個這樣的分類器,通過投票取最大的分類,則能達(dá)到接近75%的精度。分類器越多精度更高。

??需要注意:上面的情況只有每個分類器完全獨立才能達(dá)到這種程度,相似的分類器很可能會犯同樣的錯誤,所以會有大部分錯誤的選票,降低集體的準(zhǔn)確性。因此獲得不同分類器的一種方法是使用非常不同的算法來訓(xùn)練。這增加了會犯很多不同類型錯誤的機(jī)會,從而提高了整體的準(zhǔn)確性。

??下面是一個集成Logistic回歸,SVM分類,Random forest分類的投票分類器,實驗數(shù)據(jù)由moon產(chǎn)生,由于是硬投票,所以voting要設(shè)置為hard。

#產(chǎn)生moon數(shù)據(jù)并分開訓(xùn)練測試集 from sklearn.datasets import make_moons from sklearn.model_selection import train_test_split (X,y)=make_moons(1000,noise=0.5) X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2, random_state=42)#構(gòu)造模型和集成模型 from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import VotingClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC log_clf = LogisticRegression() rnd_clf = RandomForestClassifier() svm_clf = SVC() voting_clf = VotingClassifier( estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)], voting='hard' ) voting_clf.fit(X_train, y_train)#訓(xùn)練并預(yù)測 from sklearn.metrics import accuracy_score for clf in (log_clf, rnd_clf, svm_clf, voting_clf):clf.fit(X_train, y_train)y_pred = clf.predict(X_test)print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

??

??從結(jié)果可以看到集成的投票分類器的正確率比其中最好的分類器要高(但并不是每次都會更好,不過一般也能接近最好)。

??如果所有分類器都能夠估計分為每一類的概率,即都有predict_proba()方法,那么可以對每個分類器的概率取平均,再預(yù)測具有最高類概率的類,這被稱為軟投票(soft voting)。它通常比硬投票(hard voting)取得更好的效果,因為它給予了高度信任的投票更多的權(quán)重。 因此把voting =“soft”替換voting =“hard”,并確保所有分類器都可以估計類的概率即可。

??由于默認(rèn)情況下SVC類沒有predict_proba()方法,所以需要將它的probability參數(shù)設(shè)置為True(這將使SVC類使用交叉驗證來估計類概率,減慢訓(xùn)練速度,并且會增加一個predict_proba() 方法)。

#修改SVC類使得有predict_proba()方法,并軟投票 from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import VotingClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC log_clf = LogisticRegression() rnd_clf = RandomForestClassifier() svm_clf = SVC(probability=True) voting_clf = VotingClassifier( estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)], voting='soft' ) voting_clf.fit(X_train, y_train)#訓(xùn)練并預(yù)測 from sklearn.metrics import accuracy_score for clf in (log_clf, rnd_clf, svm_clf, voting_clf):clf.fit(X_train, y_train)y_pred = clf.predict(X_test)print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

??

??可以看到軟投票比硬投票確實要好一點。?


2、Bagging and Pasting

??上述獲得多種分類器的方式是使用不同的訓(xùn)練算法。另一種方法是對每個分類器使用相同的算法,但是要在訓(xùn)練集的不同隨機(jī)子集上進(jìn)行訓(xùn)練。如果抽樣時有放回,稱為Bagging;當(dāng)抽樣沒有放回,稱為Pasting。抽樣與培訓(xùn)過程如圖所示。

??

??與投票分類器一樣,最后結(jié)果預(yù)測為被預(yù)測最多的類(分類問題)或平均值(回歸問題)。一般來說,相比在完整的訓(xùn)練數(shù)據(jù)上得到的結(jié)果,集成學(xué)習(xí)得到的結(jié)果具有類似的偏差和較低的方差。而且這種算法具有并行性。

??下面使用bagging算法訓(xùn)練模型,選擇決策樹分類器作為訓(xùn)練算法;n_estimators表示產(chǎn)生分類器的數(shù)目;max_samples為每個分類器分得的樣本數(shù);bootstrap=True表示使用bagging算法,否則為pasting算法;n_jobs表示使用CPU核的數(shù)目,-1代表把能用的都用上。

from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier bag_clf = BaggingClassifier( DecisionTreeClassifier(), n_estimators=500, max_samples=100, bootstrap=True, n_jobs=-1 ) bag_clf.fit(X_train, y_train) y_pred = bag_clf.predict(X_test) print(bag_clf.__class__.__name__, accuracy_score(y_test, y_pred))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

??

??可以看到算法比前面三個算法集成的投票分類器正確率還要高一點。相比pasting算法,bagging算法偏差會稍微高一些,但是方差更小,通常能取得不錯的效果,所以通常情況下人們更愿意用bagging算法。

Out-of-Bag Evaluation

??由于bagging算法采用有放回的抽樣方式(自助采樣法),假設(shè)訓(xùn)練集有m個樣本,每次抽取一個后放回,直到抽到m個樣本,那么樣本始終沒有被抽到的概率為(1?1m)m(1?1m)m,取極限得

limm(1?1m)m=1e0.368limm→∞?(1?1m)m=1e≈0.368
??這意味對于每一個分類器大約有36.8%的樣本沒有用于訓(xùn)練,這樣的樣本成為Out-of-Bag,所以可以使用這些樣本得到結(jié)果的平均值來用于驗證模型,而不需要劃分訓(xùn)練驗證集或交叉驗證。在Scikit-learn中只需要設(shè)置參數(shù)oob_score=True即可使用這種方法估計。

bag_clf = BaggingClassifier( DecisionTreeClassifier(), n_estimators=500, bootstrap=True, n_jobs=-1, oob_score=True) bag_clf.fit(X_train, y_train) print("oob", bag_clf.oob_score_)from sklearn.metrics import accuracy_score y_pred = bag_clf.predict(X_test) print("test", accuracy_score(y_test, y_pred))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

??

??可以看到兩個精度還是比較相似的,因此可以用與模型的驗證。?


3、Random Patches and Random Subspaces

??除了能隨機(jī)選樣本創(chuàng)建多個子分類器以外還能夠隨機(jī)選擇特征來創(chuàng)建多個子分類器,通過參數(shù)max_features和bootstrap_features實現(xiàn),其含義與max_samples和bootstrap類似。對特征進(jìn)行采樣能夠提升模型的多樣性,增加偏差,減少方差。

??當(dāng)處理高維(多特征)數(shù)據(jù)(例如圖像)時,這種方法比較有用。同時對訓(xùn)練數(shù)據(jù)和特征進(jìn)行抽樣稱為Random Patches,只針對特征抽樣而不針對訓(xùn)練數(shù)據(jù)抽樣是Random Subspaces。?


隨機(jī)森林(Random forest)

??隨機(jī)森林算法是以決策樹算法為基礎(chǔ),通過bagging算法采樣訓(xùn)練樣本,再抽樣特征,3者組合成的算法。對應(yīng)的scikit-learn中為RandomForestClassifier(RandomForestRegression),它有這決策樹(DecisionTreeClassifier)的所有參數(shù),以及bagging(BaggingClassifier)的所有參數(shù)。下面是一個例子:

from sklearn.ensemble import RandomForestClassifier rnd_clf = RandomForestClassifier(n_estimators=500, max_leaf_nodes=16, n_jobs=-1) rnd_clf.fit(X_train, y_train) y_pred_rf = rnd_clf.predict(X_test)
  • 1
  • 2
  • 3
  • 4

Extra-Trees

??隨機(jī)森林算法每個分類器是從隨機(jī)抽樣部分特征,然后選擇最優(yōu)特征來劃分。如果在此基礎(chǔ)上使用隨機(jī)的閾值分割這個最優(yōu)特征,而不是最優(yōu)的閾值,這就是Extra-Trees(Extremely Randomized Trees)。這會再次增加偏差,減少方差。一般來說,Extra-Trees訓(xùn)練速度優(yōu)于隨機(jī)森林,因為尋找最優(yōu)的閾值比隨機(jī)閾值耗時。對應(yīng)scikit-learn的類為ExtraTreesClassifier(ExtraTreesRegressor),參數(shù)與隨機(jī)森林相同。

??Extra-tree和隨機(jī)森林哪個更好不好比較,只能通過交叉驗證兩種算法都實驗一次才能知道結(jié)果。

特征重要性(Feature Importance)

??由于決策樹算法根據(jù)最優(yōu)特征分層劃分的,即根部的特征更為重要,而底部的特征不重要(不出現(xiàn)的特征更不重要)。根據(jù)這個可以判斷特征的重要程度,在Scikit-learn可以通過feature_importance獲得特征的重要程度。下面iris數(shù)據(jù)訓(xùn)練一個隨機(jī)森林模型,輸出特征的重要程度。

from sklearn.datasets import load_iris iris = load_iris() rnd_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1) rnd_clf.fit(iris["data"], iris["target"]) for name, score in zip(iris["feature_names"], rnd_clf.feature_importances_):print(name, score)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

??

??可以看到petal length的重要性為44%,petal width為43%;

??隨機(jī)森林還能對圖像中像素(特征)的重要程度,下面以MNIST圖像為例子。

import matplotlib.pyplot as plt import matplotlib from sklearn.datasets import fetch_mldata mnist = fetch_mldata('MNIST original') rnd_clf = RandomForestClassifier(random_state=42) rnd_clf.fit(mnist["data"], mnist["target"])importances = rnd_clf.feature_importances_.reshape(28, 28) plt.imshow(importances, cmap = matplotlib.cm.hot) plt.colorbar(ticks=[rnd_clf.feature_importances_.min(), rnd_clf.feature_importances_.max()])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

?????????????


4、Boosting

??Boosting是將弱學(xué)習(xí)器集成為強(qiáng)學(xué)習(xí)器的方法,主要思想是按順序訓(xùn)練學(xué)習(xí)器,以嘗試修改之前的學(xué)習(xí)器。Boosting的方法有許多,最為有名的方法為AdaBoost(Adaptive Boosting)和Gradient Boosting。

??AdaBoost

??一個新的學(xué)習(xí)器會更關(guān)注之前學(xué)習(xí)器分類錯誤的訓(xùn)練樣本。因此新的學(xué)習(xí)器會越來越多地關(guān)注困難的例子。這種技術(shù)成為AdaBoost。

??

??下面介紹AdaBoost算法是怎么工作的:

??(1)假設(shè)有m個訓(xùn)練樣本,初始化每個樣本的權(quán)值w(i)w(i)1m1m,經(jīng)過第j個學(xué)習(xí)器訓(xùn)練以后,對訓(xùn)練樣本計算加權(quán)錯誤率rjrj:

rj=i=1y^j(i)y(i)mw(i)i=1mw(i)rj=∑i=1y^j(i)≠y(i)mw(i)∑i=1mw(i)
??(2)然后計算每個學(xué)習(xí)器對應(yīng)的權(quán)值αjαj。(如下圖)當(dāng)rjrj比較小時,說明該學(xué)習(xí)器的準(zhǔn)確率越高,比隨機(jī)猜(0.5)越好,分配的權(quán)值也越大;如果隨機(jī)猜(0.5),權(quán)值為0;如果小于隨機(jī)猜,則為負(fù)值。其中ηη為學(xué)習(xí)率(和梯度下降法有點相似)?
αj=ηlog1?rjrjαj=ηlog?1?rjrj
?? ?? ?? ?? ?? ??

??(3)更新樣本權(quán)值w(i)w(i),將沒有預(yù)測出來的樣本權(quán)值變大,以便后續(xù)的學(xué)習(xí)器重點訓(xùn)練。當(dāng)然這個計算完以后需要歸一化。?

w(i)?=?w(i)y^j(i)?=?y(i)w(i)?=?w(i)exp(αj)y^j(i)y(i)w(i)?=?w(i)y^j(i)?=?y(i)w(i)?=?w(i)exp?(αj)y^j(i)≠y(i)
??(4)重復(fù)(1)(2)(3)步驟不斷更新權(quán)值和訓(xùn)練新的學(xué)習(xí)器,直到學(xué)習(xí)器到一定的數(shù)目。

??(5)最終得到N個學(xué)習(xí)器,計算每個學(xué)習(xí)器對樣本的加權(quán)和,并預(yù)測為加權(quán)后最大的一類。

y^(x)=argmaxkj=1y^j(x)=kNαjy^(x)=arg?maxk∑j=1y^j(x)=kNαj

??可以看到上述的AdaBoost是二分類學(xué)習(xí)器,Scikit-learn中對應(yīng)為AdaBoostClassifier類,如果要多分類,則可以設(shè)置參數(shù)algorithm=”SAMME”,如果需要predict_proba()方法,則設(shè)置參數(shù)algorithm=”SAMME.R”,下面為以決策樹為基學(xué)習(xí)器,的多分類任務(wù)例子。

from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import AdaBoostClassifier ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), n_estimators=200,algorithm="SAMME.R", learning_rate=0.5) ada_clf.fit(X_train, y_train)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

??需要注意:SVM算法由于訓(xùn)練速度慢且不穩(wěn)定,所以不適合AdaBoost的基算法;如果產(chǎn)生過擬合可以減少學(xué)習(xí)器的數(shù)目;AdaBoost的缺點為不能并行,由于每一個學(xué)習(xí)器依賴上一個學(xué)習(xí)器。



Gradient Boosting

??和AdaBoost類似,Gradient Boosting也是逐個訓(xùn)練學(xué)習(xí)器,嘗試糾正前面學(xué)習(xí)器的錯誤。不同的是,AdaBoost糾正錯誤的方法是更加關(guān)注前面學(xué)習(xí)器分錯的樣本,Gradient Boosting(適合回歸任務(wù))糾正錯誤的方法是擬合前面學(xué)習(xí)器的殘差(預(yù)測值減真實值)。

??下面訓(xùn)練以決策樹回歸為基算法,根據(jù)上一個學(xué)習(xí)器的殘差訓(xùn)練3個學(xué)習(xí)器。數(shù)據(jù)使用二次加噪聲數(shù)據(jù)。

import numpy.random as rnd from sklearn.tree import DecisionTreeRegressor #準(zhǔn)備數(shù)據(jù) X = rnd.rand(200, 1) - 1 y = 3*X**2 + 0.05 * rnd.randn(200,1) #訓(xùn)練第一個模型 tree_reg1 = DecisionTreeRegressor(max_depth=2) tree_reg1.fit(X, y) #根據(jù)上一個模型的殘差訓(xùn)練第二個模型 y2 = y - tree_reg1.predict(X) tree_reg2 = DecisionTreeRegressor(max_depth=2) tree_reg2.fit(X, y2) #再根據(jù)上一個模型的殘差訓(xùn)練第三個模型 y3 = y2 - tree_reg2.predict(X) tree_reg3 = DecisionTreeRegressor(max_depth=2) tree_reg3.fit(X, y3) #預(yù)測 X_new=0.5 y_pred = sum(tree.predict(X_new) for tree in (tree_reg1, tree_reg2, tree_reg3))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

??

??如果將結(jié)果畫成圖,我們可以看到左側(cè)為每個學(xué)習(xí)器的決策線,有圖為相加后的結(jié)果,可以發(fā)現(xiàn)擬合效果越來越好。對應(yīng)Scikit-learn中的函數(shù)為GradientBoostingRegressor(決策樹為基)。

from sklearn.ensemble import GradientBoostingRegressor gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=3, learning_rate=1.0) gbrt.fit(X, y)
  • 1
  • 2
  • 3

??參數(shù)learning_rate表示每個學(xué)習(xí)器的貢獻(xiàn)程度,如果設(shè)置learning_rate比較低,則需要較多的學(xué)習(xí)器擬合訓(xùn)練數(shù)據(jù),但是通常會得到更好的效果。下圖展示較低學(xué)習(xí)率的訓(xùn)練結(jié)果,左圖學(xué)習(xí)器過少,欠擬合;右圖學(xué)習(xí)器過多,過擬合。

????????

為了找到最優(yōu)學(xué)習(xí)器的數(shù)量,可以使用early stopping方法(在第5節(jié)講到)。對應(yīng)可以使用staged_predict()方法,該方法能夠返回每增加一個學(xué)習(xí)器的預(yù)測結(jié)果。下面為一個實例:

import numpy as np from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error X_train, X_val, y_train, y_val = train_test_split(X, y) gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=120) gbrt.fit(X_train, y_train) errors = [mean_squared_error(y_val, y_pred) for y_pred in gbrt.staged_predict(X_val)] bst_n_estimators = np.argmin(errors) gbrt_best = GradientBoostingRegressor(max_depth=2,n_estimators=bst_n_estimators) gbrt_best.fit(X_train, y_train)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

??還可以與第5節(jié)中一樣通過設(shè)置warm_start = True使模型繼續(xù)訓(xùn)練,當(dāng)認(rèn)為不能再下降時停止,而不是訓(xùn)練完最大數(shù)目的學(xué)習(xí)器再找最小錯誤的。下面為連續(xù)迭代五次的錯誤沒有改善時,停止訓(xùn)練:

gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=1, learning_rate=0.1, random_state=42, warm_start=True) min_val_error = float("inf") error_going_up = 0 for n_estimators in range(1, 120):gbrt.n_estimators = n_estimatorsgbrt.fit(X_train, y_train)y_pred = gbrt.predict(X_val)val_error = mean_squared_error(y_val, y_pred)if val_error < min_val_error:min_val_error = val_errorerror_going_up = 0else:error_going_up += 1if error_going_up == 5:break # early stopping print gbrt.n_estimators
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

??GradientBoostingRegressor類可以通過設(shè)置參數(shù)subsample,來確定每棵樹訓(xùn)練的樣本比例,這如上面的bagging一樣,可以獲得較低的方差和高的偏差。但也大大加快訓(xùn)練速度。這種技術(shù)被稱為Stochastic Gradient Boosting。

??需要注意:Gradient Boosting還可以選擇其他損失函數(shù),通過設(shè)置參數(shù)loss來代替殘差?


5、Stacking

??上述的模型都是通過訓(xùn)練多個學(xué)習(xí)器后分別得到結(jié)果后整合為最終結(jié)果,整合的過程為投票、求平均、求加權(quán)平均等統(tǒng)計方法。那為什么不把每個學(xué)習(xí)器得到的結(jié)果作為特征進(jìn)行訓(xùn)練(Blend),再預(yù)測出最后的結(jié)果,這就是Stacking的思想。

??????????????

??為了上述思想,需要將訓(xùn)練數(shù)據(jù)分為兩部分。第1部分用于訓(xùn)練多個基學(xué)習(xí)器。

??????????

??第2部分(hold-out set)用于訓(xùn)練blender。blender的輸入為第2部分?jǐn)?shù)據(jù)在第一部分?jǐn)?shù)據(jù)訓(xùn)練好的多個模型的預(yù)測結(jié)果。

??????????

??實際上可以訓(xùn)練多個blender(如一個Logistic回歸,另一個Ramdomforest)實現(xiàn)這個思想的訣竅是將訓(xùn)練集分成三份,第一份用于訓(xùn)練多個基學(xué)習(xí)器,第二份用于訓(xùn)練第二個層(使用第一個層的預(yù)測器進(jìn)行的預(yù)測作為輸入),第三份用于訓(xùn)練第三層(使用第二層的預(yù)測器進(jìn)行的預(yù)測作為輸入)。如圖所示。

??????????

??不幸的是,scikit-learn沒有提供stacking的實現(xiàn),但是實現(xiàn)并不困難,可以參見(https://github.com/viisar/brew)。?

總結(jié)

以上是生活随笔為你收集整理的机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(八)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。