Greygt/data-mining-tools
0
1# Import all necessary libraries2import gradio as gr3import math4import pandas as pd5import numpy as np6from sklearn.preprocessing import OneHotEncoder, LabelEncoder7from sklearn.tree import DecisionTreeClassifier, plot_tree8import matplotlib.pyplot as plt9import io10import contextlib11 12# ==============================================================================13# TAB 1 FUNCTIONS: MUTUAL INFORMATION CALCULATOR14# ==============================================================================15 16def calculate_mutual_information(ug_a, ug_b, ug_c, g_a, g_b, g_c):17 """18 Calculates probabilities, entropies, and mutual information based on the19 provided student and grade counts, returning a formatted text output.20 """21 22 # Define data and total number of students23 total_students = ug_a + ug_b + ug_c + g_a + g_b + g_c24 if total_students == 0:25 return "Error: Total number of students cannot be 0.", ""26 27 counts = {28 'undergrad_A': ug_a, 'undergrad_B': ug_b, 'undergrad_C': ug_c,29 'grad_A': g_a, 'grad_B': g_b, 'grad_C': g_c30 }31 32 # --- Marginal Probabilities ---33 count_undergrad = ug_a + ug_b + ug_c34 count_grad = g_a + g_b + g_c35 p_undergrad = count_undergrad / total_students36 p_grad = count_grad / total_students37 38 count_A = ug_a + g_a39 count_B = ug_b + g_b40 count_C = ug_c + g_c41 p_A = count_A / total_students42 p_B = count_B / total_students43 p_C = count_C / total_students44 45 # --- Individual Entropies ---46 entropy_status = 047 if p_undergrad > 0: entropy_status -= p_undergrad * math.log2(p_undergrad)48 if p_grad > 0: entropy_status -= p_grad * math.log2(p_grad)49 50 entropy_grade = 051 if p_A > 0: entropy_grade -= p_A * math.log2(p_A)52 if p_B > 0: entropy_grade -= p_B * math.log2(p_B)53 if p_C > 0: entropy_grade -= p_C * math.log2(p_C)54 55 # --- Joint Entropy ---56 joint_entropy = 057 for count in counts.values():58 if count > 0:59 p_joint = count / total_students60 joint_entropy -= p_joint * math.log2(p_joint)61 62 # --- Mutual Information ---63 mutual_information = entropy_status + entropy_grade - joint_entropy64 65 # Prepare the results as formatted text66 results = f"""67 ### Marginal Probabilities68 - **P(Status=Undergrad):** {p_undergrad:.4f} ({count_undergrad}/{total_students})69 - **P(Status=Grad):** {p_grad:.4f} ({count_grad}/{total_students})70 - **P(Grade=A):** {p_A:.4f} ({count_A}/{total_students})71 - **P(Grade=B):** {p_B:.4f} ({count_B}/{total_students})72 - **P(Grade=C):** {p_C:.4f} ({count_C}/{total_students})73 74 ### Individual Entropies75 - **Entropy of Student Status, H(Status):** {entropy_status:.4f}76 - **Entropy of Grade, H(Grade):** {entropy_grade:.4f}77 78 ### Joint Entropy79 - **Joint Entropy, H(Status, Grade):** {joint_entropy:.4f}80 81 ---82 83 ### FINAL RESULT: MUTUAL INFORMATION84 **I(Status; Grade) = H(Status) + H(Grade) - H(Status, Grade)**85 **I(Status; Grade) = {entropy_status:.4f} + {entropy_grade:.4f} - {joint_entropy:.4f} = {mutual_information:.4f}**86 """87 88 summary = f"""89 - **H(Status):** {entropy_status:.4f}90 - **H(Grade):** {entropy_grade:.4f}91 - **H(Status, Grade):** {joint_entropy:.4f}92 - **Mutual Information I(Status; Grade):** {mutual_information:.4f}93 """94 95 return results, summary96 97# ==============================================================================98# TAB 2 FUNCTIONS: DECISION TREE BUILDER99# ==============================================================================100 101def calculate_entropy(data_column):102 class_counts = data_column.value_counts()103 total_samples = len(data_column)104 entropy = 0105 for count in class_counts:106 probability = count / total_samples107 if probability > 0:108 entropy -= probability * np.log2(probability)109 return entropy110 111def generate_decision_tree(df):112 """113 Calculates the steps for building a Decision Tree from a given DataFrame,114 plots the tree, and returns the steps as text and the plot object.115 """116 log_stream = io.StringIO()117 with contextlib.redirect_stdout(log_stream):118 # --- Data Preprocessing and Validation ---119 if df.shape[1] < 2:120 return "Error: The dataset must contain at least one feature and one target column.", None121 122 target_name = df.columns[-1]123 feature_names = df.columns[:-1].tolist()124 125 # --- Initial Entropy ---126 initial_entropy = calculate_entropy(df[target_name])127 print(f"### 1. Initial Entropy (Root Node) H(S)")128 print(f"Target Column: '{target_name}'")129 print(f"H(S) = {initial_entropy:.4f}\n")130 131 # --- Information Gain ---132 print("### 2. Calculating Information Gain for Each Attribute\n")133 gains = {}134 for attribute in feature_names:135 total_entropy = initial_entropy136 weighted_entropy = 0137 attribute_values = df[attribute].unique()138 print(f"--- Information Gain for '{attribute}' ---")139 for value in attribute_values:140 subset = df[df[attribute] == value]141 subset_entropy = calculate_entropy(subset[target_name])142 weight = len(subset) / len(df)143 weighted_entropy += weight * subset_entropy144 print(f" Value='{value}': Weight={weight:.2f}, Entropy={subset_entropy:.4f}")145 146 information_gain = total_entropy - weighted_entropy147 gains[attribute] = information_gain148 print(f"Weighted Average Entropy E({attribute}) = {weighted_entropy:.4f}")149 print(f"Information Gain Gain({attribute}) = {total_entropy:.4f} - {weighted_entropy:.4f} = {information_gain:.4f}\n")150 151 # --- Root Node Selection ---152 if not gains:153 root_node = "N/A"154 else:155 root_node = max(gains, key=gains.get)156 print(f"### 3. Determining the Root Node")157 for attr, gain in gains.items():158 print(f"Gain({attr}) = {gain:.4f}")159 print(f"\nThe highest information gain belongs to '{root_node}'. Therefore, the **Root Node = '{root_node}'**\n")160 161 # --- Decision Tree Visualization (with Scikit-learn) ---162 print("### 4. Decision Tree Structure and Visualization")163 X_categorical = df[feature_names]164 y_target = df[target_name]165 166 # OneHotEncoder converts categorical data into a numerical format167 encoder = OneHotEncoder(sparse_output=False, handle_unknown='ignore')168 X_encoded = encoder.fit_transform(X_categorical)169 encoded_feature_names = encoder.get_feature_names_out(feature_names)170 171 # LabelEncoder converts the target variable into a numerical format172 le = LabelEncoder()173 y_encoded = le.fit_transform(y_target)174 175 model = DecisionTreeClassifier(criterion='entropy', random_state=42)176 model.fit(X_encoded, y_encoded)177 178 plt.figure(figsize=(12, 8))179 plot_tree(model,180 feature_names=encoded_feature_names,181 class_names=le.classes_,182 filled=True,183 rounded=True,184 fontsize=10)185 plt.title("Visual Representation of the Generated Decision Tree", fontsize=16)186 187 calculation_steps = log_stream.getvalue()188 return calculation_steps, plt189 190# ==============================================================================191# GRADIO INTERFACE CREATION192# ==============================================================================193 194with gr.Blocks(theme=gr.themes.Soft()) as demo:195 gr.Markdown(196 """197 This tool allows you to interactively perform the calculations from the SWE-513 Data Mining course.198 """199 )200 201 with gr.Tabs():202 # --- TAB 1: MUTUAL INFORMATION CALCULATOR ---203 with gr.TabItem("Mutual Information Calculator"):204 with gr.Row():205 with gr.Column(scale=1):206 gr.Markdown("### Input Values\nPlease enter the student counts.")207 ua_input = gr.Number(label="Undergrad - Grade A", value=10)208 ub_input = gr.Number(label="Undergrad - Grade B", value=25)209 uc_input = gr.Number(label="Undergrad - Grade C", value=10)210 ga_input = gr.Number(label="Graduate - Grade A", value=30)211 gb_input = gr.Number(label="Graduate - Grade B", value=15)212 gc_input = gr.Number(label="Graduate - Grade C", value=10)213 btn_quiz1 = gr.Button("Calculate", variant="primary")214 with gr.Column(scale=2):215 gr.Markdown("### Calculation Summary")216 summary_output_q1 = gr.Markdown()217 gr.Markdown("### Detailed Results")218 detailed_output_q1 = gr.Markdown()219 220 # --- TAB 2: DECISION TREE BUILDER ---221 with gr.TabItem("Decision Tree Builder"):222 with gr.Row():223 with gr.Column(scale=1):224 gr.Markdown("### Input Dataset\nYou can edit the table below or paste your own data.")225 # Sample dataset from Quiz-2226 initial_df = pd.DataFrame({227 'Age': ['Young', 'Middle-age', 'Young', 'Older', 'Middle-age'],228 'Weight': ['Thin', 'Thin', 'Fat', 'Thin', 'Fat'],229 'Diagnosis': ['Negative', 'Negative', 'Negative', 'Positive', 'Positive']230 })231 df_input = gr.Dataframe(232 value=initial_df, 233 headers=['Age', 'Weight', 'Diagnosis'], 234 row_count=5, 235 col_count=(3, "fixed"),236 label="Dataset (The last column should be the target)"237 )238 btn_quiz2 = gr.Button("Generate Decision Tree", variant="primary")239 with gr.Column(scale=2):240 gr.Markdown("### Calculation Steps")241 steps_output_q2 = gr.Markdown()242 gr.Markdown("### Visualized Decision Tree")243 plot_output_q2 = gr.Plot()244 245 # Connect button clicks to their respective functions246 btn_quiz1.click(247 fn=calculate_mutual_information, 248 inputs=[ua_input, ub_input, uc_input, ga_input, gb_input, gc_input], 249 outputs=[detailed_output_q1, summary_output_q1]250 )251 252 btn_quiz2.click(253 fn=generate_decision_tree,254 inputs=df_input,255 outputs=[steps_output_q2, plot_output_q2]256 )257 258# Launch the interface259if __name__ == "__main__":260 demo.launch()