File size: 6,328 Bytes
114cfce
 
24c629e
a9bf4b6
 
114cfce
 
24c629e
114cfce
a9bf4b6
20b258b
 
 
 
 
 
 
a9bf4b6
2e5d1c7
15fffc3
a9bf4b6
 
 
15fffc3
a9bf4b6
 
 
 
15fffc3
 
a9bf4b6
 
 
687c512
a9bf4b6
 
 
 
 
 
 
20b258b
a9bf4b6
 
20b258b
687c512
 
 
20b258b
114cfce
24c629e
20b258b
114cfce
20b258b
 
a9bf4b6
24c629e
20b258b
 
114cfce
24c629e
20b258b
24c629e
20b258b
24c629e
 
a9bf4b6
20b258b
114cfce
 
 
15fffc3
114cfce
 
20b258b
 
 
 
15fffc3
20b258b
 
 
114cfce
20b258b
 
114cfce
20b258b
 
 
15fffc3
20b258b
 
15fffc3
 
 
 
 
 
 
20b258b
 
 
 
 
 
 
 
 
 
15fffc3
 
 
 
 
20b258b
 
 
 
a9bf4b6
 
24c629e
15fffc3
24c629e
 
 
687c512
 
 
24c629e
 
 
 
 
15fffc3
20b258b
 
 
 
 
 
 
a9bf4b6
24c629e
20b258b
15fffc3
 
114cfce
24c629e
20b258b
24c629e
 
 
 
 
 
114cfce
 
 
15fffc3
24c629e
a9bf4b6
2e5d1c7
a9bf4b6
20b258b
114cfce
20b258b
 
 
 
e123993
20b258b
 
 
687c512
20b258b
 
 
e123993
24c629e
20b258b
 
 
 
 
 
 
 
687c512
20b258b
 
 
 
687c512
20b258b
 
 
114cfce
 
15fffc3
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import gradio as gr
import numpy as np
import plotly.graph_objects as go
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import mean_squared_error, accuracy_score

# ------------------------------------------------
# DATA GENERATORS
# ------------------------------------------------

def generate_2d_regression(n_points, noise):
    n_points = int(n_points)
    X = np.linspace(0, 10, n_points)
    y = 2.5 * X + 5 + np.random.randn(n_points) * noise
    return X.reshape(-1, 1), y


def generate_3d_regression(n_points, noise):
    n_points = int(n_points)

    x1 = np.linspace(0, 10, n_points)
    x2 = np.linspace(0, 10, n_points)
    X1, X2 = np.meshgrid(x1, x2)

    Z = 3 * X1 + 2 * X2 + 10 + np.random.randn(*X1.shape) * noise

    X_flat = np.column_stack((X1.ravel(), X2.ravel()))
    Z_flat = Z.ravel()

    return X1, X2, X_flat, Z_flat


def generate_classification(n_points, noise):
    n_points = int(n_points)
    X = np.random.randn(n_points, 2)
    y = (X[:, 0]**2 + X[:, 1] > 0.5).astype(int)
    X += np.random.randn(*X.shape) * noise * 0.1
    return X, y


# ------------------------------------------------
# 2D RANDOM FOREST REGRESSION
# ------------------------------------------------

def rf_2d_view(n_points, noise, n_estimators, max_depth):
    n_estimators = int(n_estimators)
    max_depth = int(max_depth)

    X, y = generate_2d_regression(n_points, noise)

    rf = RandomForestRegressor(n_estimators=n_estimators, max_depth=max_depth, random_state=42)
    rf.fit(X, y)

    y_pred = rf.predict(X)
    mse = mean_squared_error(y, y_pred)

    fig = go.Figure()
    fig.add_scatter(x=X.flatten(), y=y, mode="markers", name="Data")
    fig.add_scatter(x=X.flatten(), y=y_pred, mode="lines", name="RF Prediction")

    fig.update_layout(
        title="2D Random Forest Regression",
        paper_bgcolor="#0b1e3d",
        plot_bgcolor="#0b1e3d",
        font=dict(color="white")
    )

    return fig, f"MSE: {mse:.4f}"


# ------------------------------------------------
# 3D RANDOM FOREST REGRESSION (ROTATING)
# ------------------------------------------------

def rf_3d_view(n_points, noise, n_estimators, max_depth):
    n_estimators = int(n_estimators)
    max_depth = int(max_depth)

    X1, X2, X_flat, Z_flat = generate_3d_regression(n_points, noise)

    rf = RandomForestRegressor(n_estimators=n_estimators, max_depth=max_depth, random_state=42)
    rf.fit(X_flat, Z_flat)

    Z_pred = rf.predict(X_flat).reshape(X1.shape)
    mse = mean_squared_error(Z_flat, Z_pred.ravel())

    fig = go.Figure()
    fig.add_surface(x=X1, y=X2, z=Z_pred, colorscale="Blues", opacity=0.9)

    # Smooth rotation frames
    frames = []
    for angle in range(0, 360, 10):
        frames.append(go.Frame(layout=dict(scene_camera=dict(
            eye=dict(
                x=np.cos(np.radians(angle)) * 2,
                y=np.sin(np.radians(angle)) * 2,
                z=1.2
            )
        ))))
    fig.frames = frames

    fig.update_layout(
        title="3D Random Forest Regression",
        scene=dict(bgcolor="#0b1e3d"),
        paper_bgcolor="#0b1e3d",
        font=dict(color="white"),
        updatemenus=[dict(
            type="buttons",
            showactive=False,
            buttons=[dict(
                label="Rotate 3D",
                method="animate",
                args=[None, {"frame": {"duration": 60, "redraw": True}, "fromcurrent": True}]
            )]
        )]
    )

    return fig, f"MSE: {mse:.4f}"


# ------------------------------------------------
# CLASSIFICATION VIEW
# ------------------------------------------------

def classification_view(n_points, noise, n_estimators, max_depth):
    n_estimators = int(n_estimators)
    max_depth = int(max_depth)

    X, y = generate_classification(n_points, noise)

    rf = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth, random_state=42)
    rf.fit(X, y)

    # decision boundary
    xx, yy = np.meshgrid(
        np.linspace(X[:, 0].min() - 1, X[:, 0].max() + 1, 100),
        np.linspace(X[:, 1].min() - 1, X[:, 1].max() + 1, 100)
    )

    Z = rf.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
    acc = accuracy_score(y, rf.predict(X))

    fig = go.Figure()
    fig.add_contour(x=xx[0], y=yy[:, 0], z=Z, showscale=False, opacity=0.4, colorscale="Blues")
    fig.add_scatter(x=X[:, 0], y=X[:, 1], mode="markers",
                    marker=dict(color=y, colorscale="Blues"), name="Data")

    fig.update_layout(
        title="Random Forest Classification Boundary",
        paper_bgcolor="#0b1e3d",
        plot_bgcolor="#0b1e3d",
        font=dict(color="white")
    )

    return fig, f"Accuracy: {acc:.4f}"


# ------------------------------------------------
# GRADIO UI
# ------------------------------------------------

with gr.Blocks() as demo:

    gr.Markdown("# 🌲 Random Forest Learning Dashboard (2D • 3D • Classification)")

    n_points = gr.Slider(20, 100, 40, step=1, label="Number of Points")
    noise = gr.Slider(0.0, 3.0, 1.0, label="Noise Level")
    n_estimators = gr.Slider(10, 100, 50, step=1, label="Number of Trees")
    max_depth = gr.Slider(2, 15, 8, step=1, label="Tree Depth")

    with gr.Tab("📈 2D Regression"):
        plot2d = gr.Plot()
        mse2d = gr.Markdown()

    with gr.Tab("🌐 3D Regression"):
        plot3d = gr.Plot()
        mse3d = gr.Markdown()

    with gr.Tab("🧩 Classification"):
        plot_cls = gr.Plot()
        acc_cls = gr.Markdown()

    def run_all(n_points, noise, n_estimators, max_depth):
        fig2d, mse_text = rf_2d_view(n_points, noise, n_estimators, max_depth)
        fig3d, mse3d_text = rf_3d_view(n_points, noise, n_estimators, max_depth)
        fig_cls, acc_text = classification_view(n_points, noise, n_estimators, max_depth)
        return fig2d, mse_text, fig3d, mse3d_text, fig_cls, acc_text

    for inp in [n_points, noise, n_estimators, max_depth]:
        inp.change(run_all,
                   [n_points, noise, n_estimators, max_depth],
                   [plot2d, mse2d, plot3d, mse3d, plot_cls, acc_cls])

    demo.load(run_all,
              [n_points, noise, n_estimators, max_depth],
              [plot2d, mse2d, plot3d, mse3d, plot_cls, acc_cls])


demo.launch(theme=gr.themes.Soft(primary_hue="blue"))