機器學習工程師 - Udacity 項目 1: 預測波士頓房價


第一步. 導入數據

在這個項目中,你將利用馬薩諸塞州波士頓郊區的房屋信息數據訓練和測試一個模型,並對模型的性能和預測能力進行測試。通過該數據訓練后的好的模型可以被用來對房屋做特定預測---尤其是對房屋的價值。對於房地產經紀等人的日常工作來說,這樣的預測模型被證明非常有價值。

此項目的數據集來自UCI機器學習知識庫(數據集已下線)。波士頓房屋這些數據於1978年開始統計,共506個數據點,涵蓋了麻省波士頓不同郊區房屋14種特征的信息。本項目對原始數據集做了以下處理:

有16個'MEDV' 值為50.0的數據點被移除。 這很可能是由於這些數據點包含遺失或看不到的值。
有1個數據點的 'RM' 值為8.78. 這是一個異常值,已經被移除。
對於本項目,房屋的'RM', 'LSTAT','PTRATIO'以及'MEDV'特征是必要的,其余不相關特征已經被移除。
'MEDV'特征的值已經過必要的數學轉換,可以反映35年來市場的通貨膨脹效應。

運行下面區域的代碼以載入波士頓房屋數據集,以及一些此項目所需的 Python 庫。如果成功返回數據集的大小,表示數據集已載入成功。

# Import libraries necessary for this project
import numpy as np import pandas as pd from sklearn.model_selection import ShuffleSplit # Import supplementary visualizations code visuals.py
import visuals as vs # Pretty display for notebooks
%matplotlib inline # Load the Boston housing dataset
data = pd.read_csv('housing.csv') prices = data['MEDV'] features = data.drop('MEDV', axis = 1) # Success
print("Boston housing dataset has {} data points with {} variables each.".format(*data.shape))

Boston housing dataset has 489 data points with 4 variables each.

 

第二步. 分析數據

在項目的第一個部分,你會對波士頓房地產數據進行初步的觀察並給出你的分析。通過對數據的探索來熟悉數據可以讓你更好地理解和解釋你的結果。

由於這個項目的最終目標是建立一個預測房屋價值的模型,我們需要將數據集分為特征(features)和目標變量(target variable)。

特征 'RM', 'LSTAT',和 'PTRATIO',給我們提供了每個數據點的數量相關的信息。
目標變量:'MEDV',是我們希望預測的變量。
他們分別被存在 features 和 prices 兩個變量名中。

編程練習 1:基礎統計運算
你的第一個編程練習是計算有關波士頓房價的描述統計數據。我們已為你導入了 NumPy,你需要使用這個庫來執行必要的計算。這些統計數據對於分析模型的預測結果非常重要的。 在下面的代碼中,你要做的是:

計算 prices 中的 'MEDV' 的最小值、最大值、均值、中值和標准差;
將運算結果儲存在相應的變量中。

# TODO: Minimum price of the data
minimum_price = np.min(prices) # TODO: Maximum price of the data
maximum_price = np.max(prices) # TODO: Mean price of the data
mean_price = np.mean(prices) # TODO: Median price of the data
median_price = np.median(prices) # TODO: Standard deviation of prices of the data
std_price = np.std(prices) # Show the calculated statistics
print("Statistics for Boston housing dataset:\n") print("Minimum price: ${:.2f}".format(minimum_price)) print("Maximum price: ${:.2f}".format(maximum_price)) print("Mean price: ${:.2f}".format(mean_price)) print("Median price ${:.2f}".format(median_price)) print("Standard deviation of prices: ${:.2f}".format(std_price))

Statistics for Boston housing dataset:

Minimum price: $105000.00
Maximum price: $1024800.00
Mean price: $454342.94
Median price $438900.00
Standard deviation of prices: $165171.13

Tips:統計上常用的函數:

https://docs.scipy.org/doc/numpy/reference/routines.statistics.html

 

問題 1 - 特征觀察
如前文所述,本項目中我們關注的是其中三個值:'RM'、'LSTAT' 和'PTRATIO',對每一個數據點:

'RM' 是該地區中每個房屋的平均房間數量量;
'LSTAT' 是指該地區有多少百分⽐比的業主屬於是低收⼊入階層(有⼯工作但收⼊入微薄);
'PTRATIO' 是該地區的中學和⼩小學⾥里里,學⽣生和⽼老老師的數⽬目⽐比(學⽣生/⽼老老師)。

憑直覺,上述三個特征中對每一個來說,你認為增大該特征的數值,'MEDV'的值會是增大還是減小呢?每一個答案都需要你給出理由。

提示:你預期一個'RM' 值是6的房屋跟'RM' 值是7的房屋相比,價值更高還是更低呢?

問題 1 - 回答:RM增大,MEDV將增大,因為房間數量越多,價格應該就越高;LSTAT增大,MEDV將減小,因為低收入階層會選擇價格低的房子,低收入階層的人數越多,說明這里的房子比較便宜;PTRATIO增大,MEDV將減小,因為PTRATIO越低,教學質量越好,高收入階層會選擇PTRATIO低的住宅區。

Tips:補充一種判斷屬性關聯度的方法:

 

import seaborn as sns sns.heatmap(data.corr(), annot=True)

 

 

 Tips:通過可視化來支撐你的論點:

 

# 載入畫圖所需要的庫 matplotlib
import matplotlib.pyplot as plt # 使輸出的圖像以更高清的方式顯示
%config InlineBackend.figure_format = 'retina'

# 調整圖像的寬高
plt.figure(figsize=(16, 4)) for i, key in enumerate(['RM', 'LSTAT', 'PTRATIO']): plt.subplot(1, 3, i+1) plt.xlabel(key) plt.scatter(data[key], data['MEDV'], alpha=0.5)

 

 

第三步. 建立模型

編程練習2:定義衡量標准

如果不能對模型的訓練和測試的表現進行量化地評估,我們就很難衡量模型的好壞。通常我們會定義一些衡量標准,這些標准可以通過對某些誤差或者擬合程度的計算來得到。在這個項目中,你將通過運算決定系數 R2 來量化模型的表現。模型的決定系數是回歸分析中十分常用的統計信息,經常被當作衡量模型預測能力好壞的標准。

R2 的數值范圍從0至1,表示目標變量的預測值和實際值之間的相關程度平方的百分比。一個模型的 R2 值為0還不如直接用平均值來預測效果好;而一個 R2 值為1的模型則可以對目標變量進行完美的預測。從0至1之間的數值,則表示該模型中目標變量中有百分之多少能夠用特征來解釋。模型也可能出現負值的 R2,這種情況下模型所做預測有時會比直接計算目標變量的平均值差很多。

在下方代碼的 performance_metric 函數中,你要實現:

使用 sklearn.metrics 中的 r2_score 來計算 y_true 和 y_predict 的 R2 值,作為對其表現的評判。
將他們的表現評分儲存到 score 變量中。

# TODO: Import 'r2_score'
from sklearn.metrics import r2_score def performance_metric(y_true, y_predict): """ Calculates and returns the performance score between true and predicted values based on the metric chosen. """
    
    # TODO: Calculate the performance score between 'y_true' and 'y_predict'
    score = r2_score(y_true, y_predict) # Return the score
    return score

問題 2 - 擬合程度

假設一個數據集有五個數據且一個模型做出下列目標變量的預測:

真實數值 預測數值
   3.0          2.5
   -0.5         0.0
   2.0          2.1
   7.0          7.8
   4.2          5.3

你覺得這個模型已成功地描述了目標變量的變化嗎?如果成功,請解釋為什么,如果沒有,也請給出原因。

提示1:運行下方的代碼,使用 performance_metric 函數來計算 y_true 和 y_predict 的決定系數。

提示2:𝑅2R2 分數是指可以從自變量中預測的因變量的方差比例。 換一種說法:

R2 為0意味着因變量不能從自變量預測。
R2 為1意味着可以從自變量預測因變量。
R2 在0到1之間表示因變量可預測的程度。
R2 為0.40意味着 Y 中40%的方差可以從 X 預測。

# Calculate the performance of this model
score = performance_metric([3, -0.5, 2, 7, 4.2], [2.5, 0.0, 2.1, 7.8, 5.3]) print("Model has a coefficient of determination, R^2, of {:.3f}.".format(score))

Model has a coefficient of determination, R^2, of 0.923.

問題 2 - 回答:模型成功描述了目標變量的變化,因為R^2高達0.923

Tips:R^2是評價模型表現的方法之一,每個機器學習模型的建立都要有相對應的評價指標,后面我們會學到更多的評價指標。不過R^2其實也有很多局限性需要注意:

https://en.wikipedia.org/wiki/Coefficient_of_determination#Caveats
skearn對於常見的模型表現衡量方法:
http://scikit-learn.org/stable/modules/model_evaluation.html

 

編程練習 3: 數據分割與重排

接下來,你需要把波士頓房屋數據集分成訓練和測試兩個子集。通常在這個過程中,數據也會被重排列,以消除數據集中由於順序而產生的偏差。 在下面的代碼中,你需要

使用 sklearn.model_selection 中的 train_test_split, 將 features 和 prices 的數據都分成用於訓練的數據子集和用於測試的數據子集。
分割比例為:80%的數據用於訓練,20%用於測試;
選定一個數值以設定 train_test_split 中的 random_state ,這會確保結果的一致性;
將分割后的訓練集與測試集分配給 X_train, X_test, y_train 和 y_test。

# TODO: Import 'train_test_split'
from sklearn.model_selection import train_test_split # TODO: Shuffle and split the data into training and testing subsets
X_train, X_test, y_train, y_test = train_test_split(features, prices, test_size = 0.2, random_state = 17) # Success
print("Training and testing split was successful.")

Training and testing split was successful.

問題 3 - 訓練及測試

將數據集按一定比例分為訓練用的數據集和測試用的數據集對學習算法有什么好處?

如果用模型已經見過的數據,例如部分訓練集數據進行測試,又有什么壞處?

提示: 如果沒有數據來對模型進行測試,會出現什么問題?

問題 3 - 回答:將數據集分為訓練集和測試集的好處是可以檢驗模型的准確率,如果用模型已經見過的數據,可能導致模型在這部分數據上表現很好,但在別的數據上表現不好。

 

第四步. 分析模型的表現

在項目的第四步,我們來看一下不同參數下,模型在訓練集和驗證集上的表現。這里,我們專注於一個特定的算法(帶剪枝的決策樹,但這並不是這個項目的重點),和這個算法的一個參數 'max_depth'。用全部訓練集訓練,選擇不同'max_depth' 參數,觀察這一參數的變化如何影響模型的表現。畫出模型的表現來對於分析過程十分有益。

學習曲線

下方區域內的代碼會輸出四幅圖像,它們是一個決策樹模型在不同最大深度下的表現。每一條曲線都直觀得顯示了隨着訓練數據量的增加,模型學習曲線的在訓練集評分和驗證集評分的變化,評分使用決定系數 R2。曲線的陰影區域代表的是該曲線的不確定性(用標准差衡量)。

運行下方區域中的代碼,並利用輸出的圖形回答下面的問題。

# Produce learning curves for varying training set sizes and maximum depths
vs.ModelLearning(features, prices)

問題 4 - 學習曲線

選擇上述圖像中的其中一個,並給出其最大深度。
隨着訓練數據量的增加,訓練集曲線的評分有怎樣的變化?驗證集曲線呢?
如果有更多的訓練數據,是否能有效提升模型的表現呢?

提示:學習曲線的評分是否最終會收斂到特定的值?一般來說,你擁有的數據越多,模型表現力越好。但是,如果你的訓練和測試曲線以高於基准閾值的分數收斂,這是否有必要?基於訓練和測試曲線已經收斂的前提下,思考添加更多訓練點的優缺點。

問題 4 - 回答:隨着訓練數據量的增加,訓練集的評分會下降,驗證集的評分會提高;如果有更多的訓練數據,能有效提升模型的表現,但有一個上限。

Tips:更多關於學習曲線的介紹:

https://www.coursera.org/learn/machine-learning/lecture/Kont7/learning-curves
http://scikit-learn.org/stable/auto_examples/model_selection/plot_learning_curve.html

 

復雜度曲線

下列代碼內的區域會輸出一幅圖像,它展示了一個已經經過訓練和驗證的決策樹模型在不同最大深度條件下的表現。這個圖形將包含兩條曲線,一個是訓練集的變化,一個是驗證集的變化。跟學習曲線相似,陰影區域代表該曲線的不確定性,模型訓練和測試部分的評分都用的 performance_metric 函數。

運行下方區域中的代碼,並利用輸出的圖形並回答下面的問題5與問題6。

vs.ModelComplexity(X_train, y_train)

問題 5 - 偏差(bias)與方差(variance)之間的權衡取舍

當模型以最大深度 1訓練時,模型的預測是出現很大的偏差還是出現了很大的方差?
當模型以最大深度10訓練時,情形又如何呢?
圖形中的哪些特征能夠支持你的結論?

提示: 高偏差表示欠擬合(模型過於簡單),而高方差表示過擬合(模型過於復雜,以至於無法泛化)。考慮哪種模型(深度1或10)對應着上述的情況,並權衡偏差與方差。

問題 5 - 回答:當模型以最大深度1訓練時,圖中的模型預測得分只有0.4,因此模型的預測出現很大的偏差;當模型以最大深度10訓練時,圖中的陰影區域很大,模型的得分出現很大的方差;

問題 6 - 最優模型的猜測

結合問題 5 中的圖,你認為最大深度是多少的模型能夠最好地對未見過的數據進行預測?
你得出這個答案的依據是什么?

提示:查看問題5上方的圖表,並查看模型在不同 depth下的驗證分數。隨着深度的增加模型的表現力會變得更好嗎?我們在什么情況下獲得最佳驗證分數而不會使我們的模型過度復雜?請記住,奧卡姆剃刀:“在競爭性假設中,應該選擇假設最少的那一個。”

問題 6 - 回答:我認為最大深度是4的模型能夠最好地對未見過的數據進行預測;因為深度超過4之后,模型的預測得分開始下降。

 

第五步. 評估模型的表現

在項目的最后一節中,你將構建一個模型,並使用 fit_model 中的優化模型去預測客戶特征集。

問題 7- 網格搜索(Grid Search)

什么是網格搜索法?
如何用它來優化模型?

提示:在解釋網格搜索算法時,首先要理解我們為什么使用網格搜索算法,以及我們使用它的最終目的是什么。為了使你的回答更具有說服力,你還可以給出一個模型中可以使用此方法進行優化參數的示例。

問題 7 - 回答:網格搜索法通過遍歷給定的參數組合來確定最佳的參數范圍;比如決策樹中最大深度的選擇,我們可以給出一系列的最大深度的值,比如 {'max_depth': [1,2,3,4,5]},然后通過網格搜索確定哪個值得出的結果最優。

問題 8 - 交叉驗證

什么是K折交叉驗證法(k-fold cross-validation)?
GridSearchCV 是如何結合交叉驗證來完成對最佳參數組合的選擇的?
GridSearchCV 中的'cv_results_'屬性能告訴我們什么?
網格搜索為什么要使用K折交叉驗證?K折交叉驗證能夠避免什么問題?

提示:在解釋k-fold交叉驗證時,一定要理解'k'是什么,和數據集是如何分成不同的部分來進行訓練和測試的,以及基於'k'值運行的次數。 在考慮k-fold交叉驗證如何幫助網格搜索時,你可以使用特定的數據子集來進行訓練與測試有什么缺點,以及K折交叉驗證是如何幫助緩解這個問題。

問題 8 - 回答:K折交叉驗證法是指將訓練集拆分為 k 個子集,每次將其中一個子集用作測試集,剩下 k-1 個子集將組合起來構成訓練集。接着計算所有 k 次測試的平均誤差;GridSearchCV通過交叉驗證得到每個參數組合的得分,以此確定最優的參數組合;GridSearchCV 中的'cv_results_'屬性能告訴我們每個參數組合的得分;K折交叉驗證能夠避免過擬合。

編程練習 4:擬合模型

在這個練習中,你將需要將所學到的內容整合,使用決策樹算法訓練一個模型。為了得出的是一個最優模型,你需要使用網格搜索法訓練模型,以找到最佳的 'max_depth' 參數。你可以把'max_depth' 參數理解為決策樹算法在做出預測前,允許其對數據提出問題的數量。決策樹是監督學習算法中的一種。

另外,你會發現在實現的過程中是使用ShuffleSplit()作為交叉驗證的另一種形式(參見'cv_sets'變量)。雖然它不是你在問題8中描述的K-fold交叉驗證方法,但它同樣非常有用!下面的ShuffleSplit()實現將創建10個('n_splits')混洗集合,並且對於每個混洗集,數據的20%('test_size')將被用作驗證集合。當您在實現代碼的時候,請思考一下它與K-fold cross-validation的不同與相似之處。

請注意,ShuffleSplit 在 Scikit-Learn 版本0.17和0.18中有不同的參數。對於下面代碼單元格中的 fit_model 函數,您需要實現以下內容:

1.定義 'regressor' 變量: 使用 sklearn.tree 中的 DecisionTreeRegressor 創建一個決策樹的回歸函數;
2.定義 'params' 變量: 為 'max_depth' 參數創造一個字典,它的值是從1至10的數組;
3.定義 'scoring_fnc' 變量: 使用 sklearn.metrics 中的 make_scorer 創建一個評分函數。將 ‘performance_metric’ 作為參數傳至這個函數中;
4.定義 'grid' 變量: 使用 sklearn.model_selection 中的 GridSearchCV 創建一個網格搜索對象;將變量'regressor', 'params', 'scoring_fnc'和 'cross_validator' 作為參數傳至這個對象構造函數中;

# TODO: Import 'make_scorer', 'DecisionTreeRegressor', and 'GridSearchCV'
from sklearn.metrics import make_scorer from sklearn.tree import DecisionTreeRegressor from sklearn.model_selection import GridSearchCV def fit_model(X, y): """ Performs grid search over the 'max_depth' parameter for a decision tree regressor trained on the input data [X, y]. """
    
    # Create cross-validation sets from the training data
    # sklearn version 0.18: ShuffleSplit(n_splits=10, test_size=0.1, train_size=None, random_state=None)
    # sklearn versiin 0.17: ShuffleSplit(n, n_iter=10, test_size=0.1, train_size=None, random_state=None)
    cv_sets = ShuffleSplit(n_splits=10, test_size=0.20, random_state=42) # TODO: Create a decision tree regressor object
    regressor = DecisionTreeRegressor() # TODO: Create a dictionary for the parameter 'max_depth' with a range from 1 to 10
    params = {'max_depth': [1,2,3,4,5,6,7,8,9,10]} # TODO: Transform 'performance_metric' into a scoring function using 'make_scorer' 
    scoring_fnc = make_scorer(performance_metric) # TODO: Create the grid search cv object --> GridSearchCV()
    # Make sure to include the right parameters in the object:
    # (estimator, param_grid, scoring, cv) which have values 'regressor', 'params', 'scoring_fnc', and 'cv_sets' respectively.
    grid = GridSearchCV(regressor, params, scoring = scoring_fnc, cv = cv_sets) # Fit the grid search object to the data to compute the optimal model
    grid = grid.fit(X, y) # Return the optimal model after fitting the data
    return grid.best_estimator_

 

第六步. 做出預測

當我們用數據訓練出一個模型,它現在就可用於對新的數據進行預測。在決策樹回歸函數中,模型已經學會對新輸入的數據提問,並返回對目標變量的預測值。你可以用這個預測來獲取數據未知目標變量的信息,這些數據必須是不包含在訓練數據之內的。

問題 9 - 最優模型

最優模型的最大深度(maximum depth)是多少?此答案與你在問題 6所做的猜測是否相同?

運行下方區域內的代碼,將決策樹回歸函數代入訓練數據的集合,以得到最優化的模型。

# Fit the training data to the model using grid search
reg = fit_model(X_train, y_train) # Produce the value for 'max_depth'
print("Parameter 'max_depth' is {} for the optimal model.".format(reg.get_params()['max_depth']))

Parameter 'max_depth' is 4 for the optimal model.

問題 9 - 回答:最優模型的最大深度是4?此答案與我在問題 6所做的猜測相同。

問題 10 - 預測銷售價格

想像你是一個在波士頓地區的房屋經紀人,並期待使用此模型以幫助你的客戶評估他們想出售的房屋。你已經從你的三個客戶收集到以下的資訊:

你會建議每位客戶的房屋銷售的價格為多少?
從房屋特征的數值判斷,這樣的價格合理嗎?為什么?

提示:用你在分析數據部分計算出來的統計信息來幫助你證明你的答案。

運行下列的代碼區域,使用你優化的模型來為每位客戶的房屋價值做出預測。

# Produce a matrix for client data
client_data = [[5, 17, 15], # Client 1
               [4, 32, 22], # Client 2
               [8, 3, 12]]  # Client 3

# Show predictions
for i, price in enumerate(reg.predict(client_data)): print("Predicted selling price for Client {}'s home: ${:,.2f}".format(i+1, price))

Predicted selling price for Client 1's home: $412,950.00
Predicted selling price for Client 2's home: $234,529.79
Predicted selling price for Client 3's home: $896,962.50

問題 10 - 回答:客戶1的房屋售價為412,950.00 USD,這個價格合理,因為該房屋的房間數量適中,貧困階層適中,鄰近學校的學生-老師比例適中,因此價格也適中;客戶2的房屋售價為234,529.79 USD,這個價格合理,因為該房屋的房間數量較少,貧困階層較多,鄰近學校的學生-老師比例較大,因此價格偏低;客戶3的房屋售價為896,962.50 USD,這個價格合理,因為該房屋的房間數量較多,貧困階層較少,鄰近學校的學生-老師比例較小,因此價格偏低。

編程練習 5

你剛剛預測了三個客戶的房子的售價。在這個練習中,你將用你的最優模型在整個測試數據上進行預測, 並計算相對於目標變量的決定系數 R2 的值。

提示:

你可能需要用到 X_test, y_test, optimal_reg, performance_metric。
參考問題10的代碼進行預測。
參考問題2的代碼來計算R^2的值。

# TODO Calculate the r2 score between 'y_true' and 'y_predict'
 r2 = performance_metric(y_test, reg.predict(X_test)) print("Optimal model has R^2 score {:,.2f} on test data".format(r2))

Optimal model has R^2 score 0.79 on test data

問題11 - 分析決定系數

你剛剛計算了最優模型在測試集上的決定系數,你會如何評價這個結果?

問題11 - 回答:R^2 得分 0.79,我覺得這個模型性能優良。

模型健壯性

一個最優的模型不一定是一個健壯模型。有的時候模型會過於復雜或者過於簡單,以致於難以泛化新增添的數據;有的時候模型采用的學習算法並不適用於特定的數據結構;有的時候樣本本身可能有太多噪點或樣本過少,使得模型無法准確地預測目標變量。這些情況下我們會說模型是欠擬合的。

問題 12 - 模型健壯性

模型是否足夠健壯來保證預測的一致性?

提示: 執行下方區域中的代碼,采用不同的訓練和測試集執行 fit_model 函數10次。注意觀察對一個特定的客戶來說,預測是如何隨訓練數據的變化而變化的。

vs.PredictTrials(features, prices, fit_model, client_data)

Trial 1: $391,183.33
Trial 2: $411,417.39
Trial 3: $415,800.00
Trial 4: $420,622.22
Trial 5: $413,334.78
Trial 6: $411,931.58
Trial 7: $399,663.16
Trial 8: $407,232.00
Trial 9: $402,531.82
Trial 10: $413,700.00

Range in prices: $29,438.89

問題 12 - 回答:10組數據總體來說圍繞40萬USD的范圍小幅度波動,因此模型是足夠健壯的。

問題 13 - 實用性探討

簡單地討論一下你建構的模型能否在現實世界中使用?

提示:回答以下幾個問題,並給出相應結論的理由:

1978年所采集的數據,在已考慮通貨膨脹的前提下,在今天是否仍然適用?
數據中呈現的特征是否足夠描述一個房屋?
在波士頓這樣的大都市采集的數據,能否應用在其它鄉鎮地區?
你覺得僅僅憑房屋所在社區的環境來判斷房屋價值合理嗎?

問題 13 - 回答:1978年所采集的數據,考慮到通貨膨脹的前提下,價格已經不再適用了,需要換算成今天的物價水平;數據中只呈現三個特征,遠遠不能描述一個房屋,比如交通,地區等也是影響房屋價格的重要特征;在波士頓這樣的大都市采集的數據,不能應用在其它鄉鎮地區,大城市跟鄉鎮地區的物價差異較大,特別是房子;我覺得僅憑房屋所在社區的環境來判斷房屋價值不合理,這只是眾多評價標准中的一個,一個房屋的價值是多維度的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM