In [20]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
import warnings
warnings.filterwarnings ("ignore")
In [2]:
data= pd.read_csv(r"C:\Users\hp\Downloads\Dataset.csv")
Check the dataset¶
In [5]:
print(data.shape)
print(data.columns)
print(data.info())
(25192, 42)
Index(['duration', 'protocol_type', 'service', 'flag', 'src_bytes',
'dst_bytes', 'land', 'wrong_fragment', 'urgent', 'hot',
'num_failed_logins', 'logged_in', 'num_compromised', 'root_shell',
'su_attempted', 'num_root', 'num_file_creations', 'num_shells',
'num_access_files', 'num_outbound_cmds', 'is_host_login',
'is_guest_login', 'count', 'srv_count', 'serror_rate',
'srv_serror_rate', 'rerror_rate', 'srv_rerror_rate', 'same_srv_rate',
'diff_srv_rate', 'srv_diff_host_rate', 'dst_host_count',
'dst_host_srv_count', 'dst_host_same_srv_rate',
'dst_host_diff_srv_rate', 'dst_host_same_src_port_rate',
'dst_host_srv_diff_host_rate', 'dst_host_serror_rate',
'dst_host_srv_serror_rate', 'dst_host_rerror_rate',
'dst_host_srv_rerror_rate', 'class'],
dtype='str')
<class 'pandas.DataFrame'>
RangeIndex: 25192 entries, 0 to 25191
Data columns (total 42 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 duration 25192 non-null int64
1 protocol_type 25192 non-null str
2 service 25192 non-null str
3 flag 25192 non-null str
4 src_bytes 25192 non-null int64
5 dst_bytes 25192 non-null int64
6 land 25192 non-null int64
7 wrong_fragment 25192 non-null int64
8 urgent 25192 non-null int64
9 hot 25192 non-null int64
10 num_failed_logins 25192 non-null int64
11 logged_in 25192 non-null int64
12 num_compromised 25192 non-null int64
13 root_shell 25192 non-null int64
14 su_attempted 25192 non-null int64
15 num_root 25192 non-null int64
16 num_file_creations 25192 non-null int64
17 num_shells 25192 non-null int64
18 num_access_files 25192 non-null int64
19 num_outbound_cmds 25192 non-null int64
20 is_host_login 25192 non-null int64
21 is_guest_login 25192 non-null int64
22 count 25192 non-null int64
23 srv_count 25192 non-null int64
24 serror_rate 25192 non-null float64
25 srv_serror_rate 25192 non-null float64
26 rerror_rate 25192 non-null float64
27 srv_rerror_rate 25192 non-null float64
28 same_srv_rate 25192 non-null float64
29 diff_srv_rate 25192 non-null float64
30 srv_diff_host_rate 25192 non-null float64
31 dst_host_count 25192 non-null int64
32 dst_host_srv_count 25192 non-null int64
33 dst_host_same_srv_rate 25192 non-null float64
34 dst_host_diff_srv_rate 25192 non-null float64
35 dst_host_same_src_port_rate 25192 non-null float64
36 dst_host_srv_diff_host_rate 25192 non-null float64
37 dst_host_serror_rate 25192 non-null float64
38 dst_host_srv_serror_rate 25192 non-null float64
39 dst_host_rerror_rate 25192 non-null float64
40 dst_host_srv_rerror_rate 25192 non-null float64
41 class 25192 non-null str
dtypes: float64(15), int64(23), str(4)
memory usage: 8.1 MB
None
Check target variables¶
In [6]:
print("Total missing values:", data.isnull().sum().sum())
Total missing values: 0
In [7]:
print(data["class"].value_counts())
class normal 13449 anomaly 11743 Name: count, dtype: int64
In [8]:
sns.countplot(x="class", data=data)
plt.title("Normal vs Anomaly")
plt.xlabel("Class")
plt.ylabel("Number of Records")
plt.show()
Convert categorical columns into numbers¶
In [9]:
encoder = LabelEncoder()
data["protocol_type"] = encoder.fit_transform(
data["protocol_type"]
)
data["service"] = encoder.fit_transform(
data["service"]
)
data["flag"] = encoder.fit_transform(
data["flag"]
)
data["class"] = encoder.fit_transform(
data["class"]
)
In [13]:
data.head()
Out[13]:
| duration | protocol_type | service | flag | src_bytes | dst_bytes | land | wrong_fragment | urgent | hot | ... | dst_host_srv_count | dst_host_same_srv_rate | dst_host_diff_srv_rate | dst_host_same_src_port_rate | dst_host_srv_diff_host_rate | dst_host_serror_rate | dst_host_srv_serror_rate | dst_host_rerror_rate | dst_host_srv_rerror_rate | class | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | 19 | 9 | 491 | 0 | 0 | 0 | 0 | 0 | ... | 25 | 0.17 | 0.03 | 0.17 | 0.00 | 0.00 | 0.00 | 0.05 | 0.00 | 1 |
| 1 | 0 | 2 | 41 | 9 | 146 | 0 | 0 | 0 | 0 | 0 | ... | 1 | 0.00 | 0.60 | 0.88 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 1 |
| 2 | 0 | 1 | 46 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 26 | 0.10 | 0.05 | 0.00 | 0.00 | 1.00 | 1.00 | 0.00 | 0.00 | 0 |
| 3 | 0 | 1 | 22 | 9 | 232 | 8153 | 0 | 0 | 0 | 0 | ... | 255 | 1.00 | 0.00 | 0.03 | 0.04 | 0.03 | 0.01 | 0.00 | 0.01 | 1 |
| 4 | 0 | 1 | 22 | 9 | 199 | 420 | 0 | 0 | 0 | 0 | ... | 255 | 1.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 1 |
5 rows × 42 columns
Separate X and Y¶
In [12]:
X = data.drop("class", axis=1)
y = data["class"]
In [14]:
X = data.drop("class", axis=1)
y = data["class"]
Split the data¶
In [15]:
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.20,
random_state=42,
stratify=y
)
In [16]:
print("Training data:", X_train.shape)
print("Testing data:", X_test.shape)
Training data: (20153, 41) Testing data: (5039, 41)
Logistic Regression¶
In [21]:
model1 = LogisticRegression(max_iter=1000)
model1.fit(X_train, y_train)
prediction1 = model1.predict(X_test)
accuracy1 = accuracy_score(
y_test,
prediction1
)
print("Logistic Regression Accuracy:",
accuracy1)
Logistic Regression Accuracy: 0.9023615796785076
In [22]:
print(
classification_report(
y_test,
prediction1
)
)
precision recall f1-score support
0 0.96 0.83 0.89 2349
1 0.87 0.97 0.91 2690
accuracy 0.90 5039
macro avg 0.91 0.90 0.90 5039
weighted avg 0.91 0.90 0.90 5039
Decision Tree¶
In [23]:
model2 = DecisionTreeClassifier(
random_state=42
)
model2.fit(X_train, y_train)
prediction2 = model2.predict(X_test)
accuracy2 = accuracy_score(
y_test,
prediction2
)
print("Decision Tree Accuracy:",
accuracy2)
Decision Tree Accuracy: 0.9950386981543957
In [24]:
print(
classification_report(
y_test,
prediction2
)
)
precision recall f1-score support
0 0.99 0.99 0.99 2349
1 1.00 1.00 1.00 2690
accuracy 1.00 5039
macro avg 1.00 1.00 1.00 5039
weighted avg 1.00 1.00 1.00 5039
Random Forest¶
In [25]:
model3 = RandomForestClassifier(
n_estimators=100,
random_state=42
)
model3.fit(X_train, y_train)
prediction3 = model3.predict(X_test)
accuracy3 = accuracy_score(
y_test,
prediction3
)
print("Random Forest Accuracy:",
accuracy3)
Random Forest Accuracy: 0.9980154792617583
In [26]:
print(
classification_report(
y_test,
prediction3
)
)
precision recall f1-score support
0 1.00 1.00 1.00 2349
1 1.00 1.00 1.00 2690
accuracy 1.00 5039
macro avg 1.00 1.00 1.00 5039
weighted avg 1.00 1.00 1.00 5039
Compare the three models¶
In [27]:
print("Logistic Regression:",
accuracy1)
print("Decision Tree:",
accuracy2)
print("Random Forest:",
accuracy3)
Logistic Regression: 0.9023615796785076 Decision Tree: 0.9950386981543957 Random Forest: 0.9980154792617583
In [28]:
results = pd.DataFrame({
"Model": [
"Logistic Regression",
"Decision Tree",
"Random Forest"
],
"Accuracy": [
accuracy1,
accuracy2,
accuracy3
]
})
print(results)
Model Accuracy 0 Logistic Regression 0.902362 1 Decision Tree 0.995039 2 Random Forest 0.998015
In [29]:
plt.figure(figsize=(8,5))
sns.barplot(
x="Model",
y="Accuracy",
data=results
)
plt.title("Machine Learning Model Comparison")
plt.ylabel("Accuracy")
plt.xlabel("Model")
plt.xticks(rotation=20)
plt.show()
Confusion matrix for Random Forest¶
In [30]:
cm = confusion_matrix(
y_test,
prediction3
)
print(cm)
[[2341 8] [ 2 2688]]
In [31]:
plt.figure(figsize=(6,5))
sns.heatmap(
cm,
annot=True,
fmt="d",
cmap="Blues"
)
plt.title("Random Forest Confusion Matrix")
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.show()
Feature importance¶
In [32]:
importance = model3.feature_importances_
features = X.columns
importance_df = pd.DataFrame({
"Feature": features,
"Importance": importance
})
In [33]:
importance_df = importance_df.sort_values(
"Importance",
ascending=False
)
print(importance_df)
Feature Importance 4 src_bytes 0.197405 5 dst_bytes 0.088876 3 flag 0.083065 32 dst_host_srv_count 0.072693 33 dst_host_same_srv_rate 0.065365 28 same_srv_rate 0.057827 11 logged_in 0.044737 22 count 0.042408 29 diff_srv_rate 0.034526 1 protocol_type 0.034376 24 serror_rate 0.033200 34 dst_host_diff_srv_rate 0.030342 35 dst_host_same_src_port_rate 0.025441 25 srv_serror_rate 0.024180 2 service 0.024117 23 srv_count 0.019773 36 dst_host_srv_diff_host_rate 0.019657 37 dst_host_serror_rate 0.016962 39 dst_host_rerror_rate 0.014435 31 dst_host_count 0.013248 38 dst_host_srv_serror_rate 0.012314 9 hot 0.011170 40 dst_host_srv_rerror_rate 0.006958 27 srv_rerror_rate 0.005459 12 num_compromised 0.005346 7 wrong_fragment 0.004427 26 rerror_rate 0.003774 0 duration 0.003356 30 srv_diff_host_rate 0.002249 21 is_guest_login 0.001124 15 num_root 0.000376 16 num_file_creations 0.000204 10 num_failed_logins 0.000202 18 num_access_files 0.000135 13 root_shell 0.000134 8 urgent 0.000077 14 su_attempted 0.000025 17 num_shells 0.000024 6 land 0.000010 19 num_outbound_cmds 0.000000 20 is_host_login 0.000000
In [34]:
print(
importance_df.head(15)
)
Feature Importance 4 src_bytes 0.197405 5 dst_bytes 0.088876 3 flag 0.083065 32 dst_host_srv_count 0.072693 33 dst_host_same_srv_rate 0.065365 28 same_srv_rate 0.057827 11 logged_in 0.044737 22 count 0.042408 29 diff_srv_rate 0.034526 1 protocol_type 0.034376 24 serror_rate 0.033200 34 dst_host_diff_srv_rate 0.030342 35 dst_host_same_src_port_rate 0.025441 25 srv_serror_rate 0.024180 2 service 0.024117
In [35]:
top_features = importance_df.head(15)
plt.figure(figsize=(10,6))
sns.barplot(
x="Importance",
y="Feature",
data=top_features
)
plt.title(
"Top 15 Important Features"
)
plt.show()
Simple error analysis¶
In [36]:
test_results = X_test.copy()
test_results["Actual"] = y_test.values
test_results["Predicted"] = prediction3
In [38]:
errors = test_results[
test_results["Actual"]
!= test_results["Predicted"]
]
print(errors.head())
duration protocol_type service flag src_bytes dst_bytes land \
10216 0 1 19 9 334 0 0
9807 0 0 13 9 8 0 0
5036 0 1 22 1 0 0 0
18019 0 2 46 9 100 0 0
13183 0 1 17 5 0 0 0
wrong_fragment urgent hot ... dst_host_same_srv_rate \
10216 0 0 0 ... 0.33
9807 0 0 0 ... 0.01
5036 0 0 0 ... 0.00
18019 0 0 0 ... 0.03
13183 0 0 0 ... 0.05
dst_host_diff_srv_rate dst_host_same_src_port_rate \
10216 0.07 0.35
9807 0.03 0.01
5036 0.00 0.00
18019 0.06 0.03
13183 0.05 0.02
dst_host_srv_diff_host_rate dst_host_serror_rate \
10216 0.00 0.01
9807 0.97 0.00
5036 0.00 0.00
18019 0.00 0.00
13183 0.22 0.01
dst_host_srv_serror_rate dst_host_rerror_rate \
10216 0.04 0.00
9807 0.00 0.01
5036 0.00 0.00
18019 0.00 0.00
13183 0.11 0.00
dst_host_srv_rerror_rate Actual Predicted
10216 0.0 0 1
9807 0.0 0 1
5036 0.0 1 0
18019 0.0 0 1
13183 0.0 1 0
[5 rows x 43 columns]
In [39]:
print(
"Number of incorrect predictions:",
len(errors)
)
Number of incorrect predictions: 10
Simple analysis of protocol types¶
In [40]:
test_results["Protocol"] = data.loc[
X_test.index,
"protocol_type"
].values
In [41]:
print(
test_results.groupby("Protocol")[
["Actual", "Predicted"]
].mean()
)
Actual Predicted Protocol 0 0.139130 0.144928 1 0.520128 0.520869 2 0.831008 0.832558
In [42]:
for protocol in test_results["Protocol"].unique():
subset = test_results[
test_results["Protocol"] == protocol
]
acc = accuracy_score(
subset["Actual"],
subset["Predicted"]
)
print(
"Protocol:",
protocol,
"Accuracy:",
acc
)
Protocol: 1 Accuracy: 0.998271178068659 Protocol: 0 Accuracy: 0.9942028985507246 Protocol: 2 Accuracy: 0.9984496124031008
In [ ]: