===================================================================LINEAR REGRESSION=====================================================================
# Importing necessary libraries
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error

# Load the California housing dataset
california_housing = fetch_california_housing()
X = california_housing.data
y = california_housing.target

# Standard scaling the features
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Split the scaled data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)

# Create a linear regression model
model = LinearRegression()

# Fit the model on the scaled training data
model.fit(X_train, y_train)

# Make predictions on the scaled testing data
y_pred = model.predict(X_test)

# Calculate mean squared error
mse = mean_squared_error(y_test, y_pred)
print("Mean Squared Error:", mse)

# Plotting the predicted vs actual values
plt.scatter(y_test, y_pred, color='blue')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=3) # Regression line
plt.xlabel("Actual Prices")
plt.ylabel("Predicted Prices")
plt.title("Actual vs Predicted Prices")
plt.show()


===================================================================K MEANS CLUSTERING===================================================================
# Importing necessary libraries
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans

# Load the Iris dataset
iris = load_iris()
X = iris.data

# Specify the number of clusters
k = 3

# Create a k-means clustering model
kmeans = KMeans(n_clusters=k)

# Fit the model to the data
kmeans.fit(X)

# Get the cluster centroids and labels
centroids = kmeans.cluster_centers_
labels = kmeans.labels_

# Plotting the clusters
colors = ['r', 'g', 'b']  # Define colors for each cluster
for i in range(k):
    # Plot points for each cluster
    plt.scatter(X[labels == i, 0], X[labels == i, 1], c=colors[i], label=f'Cluster {i+1}')

# Plotting centroids
plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', s=200, c='black', label='Centroids')

plt.xlabel(iris.feature_names[0])
plt.ylabel(iris.feature_names[1])
plt.title('K-means Clustering on Iris Dataset')
plt.legend()
plt.show()

===================================================================DECISION TREE=========================================================================
# Importing necessary libraries
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.metrics import accuracy_score , classification_report

# Load the Iris dataset
iris = load_iris()
X = iris.data
y = iris.target

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Create a decision tree classifier
tree_classifier = DecisionTreeClassifier()

# Fit the model on the training data
tree_classifier.fit(X_train, y_train)

# Make predictions on the testing data
y_pred = tree_classifier.predict(X_test)

# Calculate accuracy
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)
print("Classification Report:", classification_report(y_test,y_pred))

# Visualize the decision tree
plt.figure(figsize=(12, 8))
plot_tree(tree_classifier, feature_names=iris.feature_names, class_names=iris.target_names, filled=True)
plt.show()


===================================================================AGGLOMERATIVE CLUSTERING============================================================
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler
from scipy.cluster.hierarchy import dendrogram, linkage

# Load the Iris dataset
iris = load_iris()
X = iris.data
y = iris.target

# Standardize the features
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Perform agglomerative clustering
cluster_model = AgglomerativeClustering(n_clusters=3)
cluster_labels = cluster_model.fit_predict(X_scaled)

# Evaluate clustering performance using silhouette score
silhouette_avg = silhouette_score(X_scaled, cluster_labels)
print("Silhouette Score:", silhouette_avg)

# Plot the clusters
plt.figure(figsize=(12, 6))

# Scatter plot
plt.subplot(1, 2, 1)
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=cluster_labels, cmap='viridis')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.title('Agglomerative Clustering of Iris Dataset')

# Dendrogram
plt.subplot(1, 2, 2)
linked = linkage(X_scaled, method='ward')
dendrogram(linked, orientation='top', distance_sort='descending', show_leaf_counts=True)
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('Sample Index')
plt.ylabel('Distance')
plt.tight_layout()

plt.show()

===================================================================HITS ALGORITHM========================================================================
import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()

G.add_edges_from([('A','D'),('B','C'),('B','E'),('C','A'),
                 ('D','D'),('B','C'),('B','A'),('E','D'),
                 ('E','A'),('B','C'),('C','B'),('C','E'),
                 ('B','D'),('A','C')])

plt.figure(figsize=(10,10))
nx.draw_networkx(G, with_labels=True)

hubs, authorities = nx.hits(G, max_iter=50, normalized=True)

print("Hubs Score:", hubs)
print("Authority Scores:", authorities)

===================================================================PAGE RANKING==========================================================================
def pagerank(graph, damping_factor=0.85, num_iterations=10):
    num_nodes = len(graph)
    # Initialize PageRank values equally for all nodes
    pagerank_values = {node: 1 / num_nodes for node in graph}

    for _ in range(num_iterations):
        new_pagerank_values = {}
        for node in graph:
            # Calculate the sum of PageRank values of nodes pointing to the current node
            incoming_pagerank = sum(pagerank_values[other_node] / len(graph[other_node]) 
                                    for other_node in graph if node in graph[other_node])
            # Update PageRank value for the current node
            new_pagerank_values[node] = (1 - damping_factor) / num_nodes + damping_factor * incoming_pagerank

        pagerank_values = new_pagerank_values

    return pagerank_values

# Example graph representing web pages and their connections
graph = {
    'A': ['B', 'C'],
    'B': ['C'],
    'C': ['A'],
    'D': ['C']
}

# Calculate PageRank
pagerank_values = pagerank(graph)
print("PageRank values:")
for node, rank in sorted(pagerank_values.items(), key=lambda x: x[1], reverse=True):
    print(f"{node}: {rank}")
==============================================================================================================================================APRIORI ALGO=========================
from collections import defaultdict

def generate_candidates(itemset, k):
    candidates = set()
    for i in range(len(itemset)):
        for j in range(i+1, len(itemset)):
            union = itemset[i] | itemset[j]
            if len(union) == k:
                candidates.add(union)
    return candidates

def prune(itemset, candidates, min_support):
    pruned = set()
    support_count = defaultdict(int)
    for transaction in itemset:
        for candidate in candidates:
            if candidate.issubset(transaction):
                support_count[candidate] += 1

    for candidate, count in support_count.items():
        support = count / len(itemset)
        if support >= min_support:
            pruned.add(candidate)

    return pruned

def apriori(itemset, min_support):
    itemset = [set(transaction) for transaction in itemset]
    k = 2
    freq_itemsets = []
    
    single_itemset = set()
    for transaction in itemset:
        for item in transaction:
            single_itemset.add(frozenset([item]))
    
    candidates = prune(itemset, single_itemset, min_support)
    freq_itemsets.extend(candidates)

    while candidates:
        candidates = generate_candidates(freq_itemsets, k)
        candidates = prune(itemset, candidates, min_support)
        freq_itemsets.extend(candidates)
        k += 1

    return freq_itemsets

# Example usage
transactions = [
    [1, 2, 3, 4],
    [1, 2, 4],
    [1, 2],
    [2, 3, 4],
    [2, 3],
    [3, 4],
    [2, 4]
]

min_support = 0.5
frequent_itemsets = apriori(transactions, min_support)
print("Frequent Itemsets:")
for itemset in frequent_itemsets:
    print(itemset)