From 7eded552ef4eabbedae61131157848a0a9f99bb5 Mon Sep 17 00:00:00 2001 From: kimayagaikwad2067-ship-it Date: Wed, 11 Mar 2026 22:58:21 +0530 Subject: [PATCH 1/2] Fix: completed basics and some intermediate exercises --- .../test_playground/advanced/boss.py | 337 ++++++++++++++++++ .../advanced/feature_engineering_pandas.py | 216 +++++++++++ .../test_playground/advanced/linalg_numpy.py | 152 ++++++++ .../advanced/matplotlib_plots.py | 136 +++++++ .../test_playground/advanced/numpy_basics.py | 152 ++++++++ .../test_playground/advanced/pandas_basics.py | 135 +++++++ .../test_playground/advanced/sklearn_stuff.py | 221 ++++++++++++ .../test_playground/assets/algo_arrays.json | 54 +++ .../test_playground/assets/attendance.csv | 51 +++ .../test_playground/assets/bills.csv | 2 + .../assets/chatbot_prompts.json | 8 + .../test_playground/assets/cipher_cases.json | 22 ++ .../test_playground/assets/cp_tests.json | 31 ++ .../test_playground/assets/demo.json | 10 + .../test_playground/assets/ds_sequences.json | 29 ++ .../assets/generate_datasets.py | 190 ++++++++++ .../assets/ml_classification.csv | 261 ++++++++++++++ .../test_playground/assets/ml_regression.csv | 221 ++++++++++++ .../test_playground/assets/sales.csv | 181 ++++++++++ .../test_playground/assets/students.csv | 13 + .../test_playground/assets/students_demo.csv | 3 + .../assets/weather_timeseries.csv | 61 ++++ .../test_playground/basics/boss.py | 54 +++ .../test_playground/basics/conditionals.py | 61 ++++ .../test_playground/basics/hello.py | 2 + .../test_playground/basics/input_output.py | 32 ++ .../test_playground/basics/loops.py | 21 ++ .../test_playground/basics/vars_and_ops.py | 25 ++ .../test_playground/intermediate/boss.py | 275 ++++++++++++++ .../intermediate/class_basics.py | 65 ++++ .../intermediate/csv_handler.py | 68 ++++ .../test_playground/intermediate/dict_ops.py | 35 ++ .../intermediate/inheritance.py | 48 +++ .../intermediate/json_handler.py | 61 ++++ .../test_playground/intermediate/lambdas.py | 30 ++ .../test_playground/intermediate/list_ops.py | 36 ++ .../test_playground/intermediate/set_ops.py | 27 ++ .../intermediate/some_functions.py | 60 ++++ .../intermediate/sql_handler.py | 93 +++++ .../test_playground/intermediate/tuple_ops.py | 29 ++ .../intermediate/txt_handler.py | 50 +++ .../miscellaneous/basic_flask_routing.py | 58 +++ .../test_playground/miscellaneous/ciphers.py | 63 ++++ .../test_playground/miscellaneous/os_path.py | 42 +++ .../miscellaneous/some_algos.py | 97 +++++ .../miscellaneous/some_cp_problems.py | 59 +++ .../miscellaneous/some_data_structures.py | 275 ++++++++++++++ .../miscellaneous/terminal_chatbot.py | 60 ++++ 48 files changed, 4212 insertions(+) create mode 100644 kimaya_solutions/test_playground/advanced/boss.py create mode 100644 kimaya_solutions/test_playground/advanced/feature_engineering_pandas.py create mode 100644 kimaya_solutions/test_playground/advanced/linalg_numpy.py create mode 100644 kimaya_solutions/test_playground/advanced/matplotlib_plots.py create mode 100644 kimaya_solutions/test_playground/advanced/numpy_basics.py create mode 100644 kimaya_solutions/test_playground/advanced/pandas_basics.py create mode 100644 kimaya_solutions/test_playground/advanced/sklearn_stuff.py create mode 100644 kimaya_solutions/test_playground/assets/algo_arrays.json create mode 100644 kimaya_solutions/test_playground/assets/attendance.csv create mode 100644 kimaya_solutions/test_playground/assets/bills.csv create mode 100644 kimaya_solutions/test_playground/assets/chatbot_prompts.json create mode 100644 kimaya_solutions/test_playground/assets/cipher_cases.json create mode 100644 kimaya_solutions/test_playground/assets/cp_tests.json create mode 100644 kimaya_solutions/test_playground/assets/demo.json create mode 100644 kimaya_solutions/test_playground/assets/ds_sequences.json create mode 100644 kimaya_solutions/test_playground/assets/generate_datasets.py create mode 100644 kimaya_solutions/test_playground/assets/ml_classification.csv create mode 100644 kimaya_solutions/test_playground/assets/ml_regression.csv create mode 100644 kimaya_solutions/test_playground/assets/sales.csv create mode 100644 kimaya_solutions/test_playground/assets/students.csv create mode 100644 kimaya_solutions/test_playground/assets/students_demo.csv create mode 100644 kimaya_solutions/test_playground/assets/weather_timeseries.csv create mode 100644 kimaya_solutions/test_playground/basics/boss.py create mode 100644 kimaya_solutions/test_playground/basics/conditionals.py create mode 100644 kimaya_solutions/test_playground/basics/hello.py create mode 100644 kimaya_solutions/test_playground/basics/input_output.py create mode 100644 kimaya_solutions/test_playground/basics/loops.py create mode 100644 kimaya_solutions/test_playground/basics/vars_and_ops.py create mode 100644 kimaya_solutions/test_playground/intermediate/boss.py create mode 100644 kimaya_solutions/test_playground/intermediate/class_basics.py create mode 100644 kimaya_solutions/test_playground/intermediate/csv_handler.py create mode 100644 kimaya_solutions/test_playground/intermediate/dict_ops.py create mode 100644 kimaya_solutions/test_playground/intermediate/inheritance.py create mode 100644 kimaya_solutions/test_playground/intermediate/json_handler.py create mode 100644 kimaya_solutions/test_playground/intermediate/lambdas.py create mode 100644 kimaya_solutions/test_playground/intermediate/list_ops.py create mode 100644 kimaya_solutions/test_playground/intermediate/set_ops.py create mode 100644 kimaya_solutions/test_playground/intermediate/some_functions.py create mode 100644 kimaya_solutions/test_playground/intermediate/sql_handler.py create mode 100644 kimaya_solutions/test_playground/intermediate/tuple_ops.py create mode 100644 kimaya_solutions/test_playground/intermediate/txt_handler.py create mode 100644 kimaya_solutions/test_playground/miscellaneous/basic_flask_routing.py create mode 100644 kimaya_solutions/test_playground/miscellaneous/ciphers.py create mode 100644 kimaya_solutions/test_playground/miscellaneous/os_path.py create mode 100644 kimaya_solutions/test_playground/miscellaneous/some_algos.py create mode 100644 kimaya_solutions/test_playground/miscellaneous/some_cp_problems.py create mode 100644 kimaya_solutions/test_playground/miscellaneous/some_data_structures.py create mode 100644 kimaya_solutions/test_playground/miscellaneous/terminal_chatbot.py diff --git a/kimaya_solutions/test_playground/advanced/boss.py b/kimaya_solutions/test_playground/advanced/boss.py new file mode 100644 index 00000000..99c39b09 --- /dev/null +++ b/kimaya_solutions/test_playground/advanced/boss.py @@ -0,0 +1,337 @@ +"""Advanced capstone: Tkinter app with three ML windows (intentional practice bugs included).""" + +from __future__ import annotations + +from pathlib import Path + +import numpy as np +import pandas as pd + +import tkinter as tk +from tkinter import ttk, messagebox + +from matplotlib.figure import Figure +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg + +from sklearn.cluster import KMeans +from sklearn.compose import ColumnTransformer +from sklearn.impute import SimpleImputer +from sklearn.linear_model import LinearRegression, LogisticRegression +from sklearn.metrics import accuracy_score, mean_absolute_error, mean_squared_error, silhouette_score +from sklearn.model_selection import train_test_split +from sklearn.pipeline import Pipeline +from sklearn.preprocessing import OneHotEncoder, StandardScaler + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +REG_PATH = ASSETS / "ml_regression.csv" +CLS_PATH = ASSETS / "ml_classification.csv" +SALES_PATH = ASSETS / "sales.csv" + + +# helper with a tiny logic bug +def quick_shape(df: pd.DataFrame) -> tuple[int, int]: + """Return (rows, columns).""" + return (len(df.columns), len(df)) # hint: shape tuple is reversed + + +# helper with a metric naming bug +def regression_rmse(y_true, y_pred) -> float: + """Return RMSE for regression predictions.""" + return float(mean_absolute_error(y_true, y_pred)) # hint: RMSE should use sqrt(mean_squared_error) + + +class MLWindow(tk.Toplevel): + """Base Toplevel window with left info panel and right plot panel.""" + + def __init__(self, master: tk.Tk, title: str): + super().__init__(master) + self.title(title) + self.geometry("1080x620") + + self.left_text: tk.Text | None = None + self.tree: ttk.Treeview | None = None + self.metric_label: ttk.Label | None = None + self.figure: Figure | None = None + self.ax = None + self.canvas: FigureCanvasTkAgg | None = None + + self._build_layout() + + def _build_layout(self) -> None: + container = ttk.Frame(self, padding=10) + container.pack(fill="both", expand=True) + container.columnconfigure(0, weight=1) + container.columnconfigure(1, weight=1) + container.rowconfigure(0, weight=1) + + left = ttk.Frame(container) + left.grid(row=0, column=0, sticky="nsew", padx=(0, 8)) + left.rowconfigure(1, weight=1) + left.columnconfigure(0, weight=1) + + self.left_text = tk.Text(left, height=10, width=50) + self.left_text.grid(row=0, column=0, sticky="ew", pady=(0, 8)) + + self.tree = ttk.Treeview(left, show="headings", height=18) + self.tree.grid(row=1, column=0, sticky="nsew") + scrollbar = ttk.Scrollbar(left, orient="vertical", command=self.tree.yview) + scrollbar.grid(row=1, column=1, sticky="ns") + self.tree.configure(yscrollcommand=scrollbar.set) + + right = ttk.Frame(container) + right.grid(row=0, column=1, sticky="nsew") + + self.figure = Figure(figsize=(5.2, 4.2), dpi=100) + self.ax = self.figure.add_subplot(111) + self.canvas = FigureCanvasTkAgg(self.figure, master=right) + self.canvas.get_tk_widget().pack(fill="both", expand=True) + + self.metric_label = ttk.Label(right, text="Metrics: N/A", font=("TkDefaultFont", 10, "bold")) + self.metric_label.pack(anchor="w", pady=(6, 0)) + + def fill_table(self, df: pd.DataFrame, n: int = 20) -> None: + if self.tree is None: + return + self.tree.delete(*self.tree.get_children()) + cols = list(df.columns) + self.tree["columns"] = cols + for col in cols: + self.tree.heading(col, text=col) + self.tree.column(col, width=110, anchor="center") + for _, row in df.head(n).iterrows(): + self.tree.insert("", "end", values=[row[c] for c in cols]) + + def fill_summary(self, df: pd.DataFrame, title: str) -> None: + if self.left_text is None: + return + r, c = quick_shape(df) + numeric = df.select_dtypes(include=[np.number]).columns.tolist() + lines = [ + title, + f"Rows: {r}", + f"Columns: {c}", + f"Column names: {', '.join(df.columns)}", + "", + "Basic stats (first 4 numeric columns):", + ] + for col in numeric[:4]: + lines.append(f"- {col}: mean={df[col].mean():.3f}, std={df[col].std():.3f}") + + self.left_text.delete("1.0", tk.END) + self.left_text.insert("1.0", "\n".join(lines)) + + def set_metrics(self, text: str) -> None: + if self.metric_label is not None: + self.metric_label.config(text=text) + + +class RegressionWindow(MLWindow): + """Regression demonstration window.""" + + def __init__(self, master: tk.Tk): + super().__init__(master, "Regression Demo") + self.render() + + def render(self) -> None: + if not REG_PATH.exists(): + messagebox.showerror("Missing dataset", f"Missing: {REG_PATH}") + self.destroy() + return + + df = pd.read_csv(REG_PATH) + self.fill_summary(df, "Regression dataset") + self.fill_table(df) + + X = df.drop(columns=["y"]) + y = df["y"] + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42) + + pipe = Pipeline( + steps=[ + ("scaler", StandardScaler()), + ("model", LinearRegression()), + ] + ) + pipe.fit(X_train, y_train) + pred = pipe.predict(X_test) + + rmse = regression_rmse(y_test, pred) + mse = float(mean_squared_error(y_test, pred)) + + self.ax.clear() + self.ax.scatter(y_test, pred, alpha=0.7, color="tab:blue", label="pred") + lims = [min(y_test.min(), pred.min()), max(y_test.max(), pred.max())] + self.ax.plot(lims, lims, "r--", label="ideal") + self.ax.set_title("Regression: Actual vs Predicted") + self.ax.set_xlabel("Actual") + self.ax.set_ylabel("Predicted") + self.ax.legend() + self.figure.tight_layout() + self.canvas.draw() + + self.set_metrics(f"Metrics: RMSE={rmse:.4f}, MSE={mse:.4f}") + + +class ClassificationWindow(MLWindow): + """Classification demonstration window.""" + + def __init__(self, master: tk.Tk): + super().__init__(master, "Classification Demo") + self.render() + + def render(self) -> None: + if not CLS_PATH.exists(): + messagebox.showerror("Missing dataset", f"Missing: {CLS_PATH}") + self.destroy() + return + + df = pd.read_csv(CLS_PATH) + self.fill_summary(df, "Classification dataset") + self.fill_table(df) + + X = df.drop(columns=["label"]) + y = df["label"] + + numeric_cols = X.select_dtypes(include=["number"]).columns.tolist() + categorical_cols = X.select_dtypes(exclude=["number"]).columns.tolist() + + pre = ColumnTransformer( + transformers=[ + ( + "num", + Pipeline([ + ("imputer", SimpleImputer(strategy="median")), + ("scaler", StandardScaler()), + ]), + numeric_cols, + ), + ( + "cat", + Pipeline([ + ("imputer", SimpleImputer(strategy="most_frequent")), + ("onehot", OneHotEncoder(handle_unknown="ignore")), + ]), + categorical_cols, + ), + ] + ) + + model = Pipeline( + steps=[ + ("pre", pre), + ("clf", LogisticRegression(max_iter=1000)), + ] + ) + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + test_size=0.3, + random_state=42, + stratify=y, + ) + model.fit(X_train, y_train) + pred = model.predict(X_test) + + acc = float(np.mean(pred == 1)) # hint: accuracy should compare pred with y_test + sk_acc = float(accuracy_score(y_test, pred)) + + self.ax.clear() + cls0 = X_test[pred == 0] + cls1 = X_test[pred == 1] + self.ax.scatter(cls0["x1"], cls0["x2"], alpha=0.65, color="tab:green", label="pred 0") + self.ax.scatter(cls1["x1"], cls1["x2"], alpha=0.65, color="tab:orange", label="pred 1") + self.ax.set_title("Classification: Predicted Classes") + self.ax.set_xlabel("x1") + self.ax.set_ylabel("x2") + self.ax.legend() + self.figure.tight_layout() + self.canvas.draw() + + self.set_metrics(f"Metrics: accuracy={acc:.4f}, sklearn_acc={sk_acc:.4f}") + + +class ClusteringWindow(MLWindow): + """Third ML window: clustering demo on sales-style numeric features.""" + + def __init__(self, master: tk.Tk): + super().__init__(master, "Clustering Demo") + self.render() + + def render(self) -> None: + if not SALES_PATH.exists(): + messagebox.showerror("Missing dataset", f"Missing: {SALES_PATH}") + self.destroy() + return + + df = pd.read_csv(SALES_PATH) + self.fill_summary(df, "Sales clustering dataset") + self.fill_table(df) + + numeric = df.select_dtypes(include=[np.number]) + if numeric.shape[1] < 2: + messagebox.showerror("Dataset error", "Sales dataset needs >=2 numeric columns for clustering") + self.destroy() + return + + X = numeric.iloc[:, :2].to_numpy() + scaler = StandardScaler() + Xs = scaler.fit_transform(X) + + km = KMeans(n_clusters=3, random_state=42, n_init=10) + labels = km.fit_predict(Xs) + + sil = float(-silhouette_score(Xs, labels)) # hint: silhouette score should not be negated + + self.ax.clear() + self.ax.scatter(Xs[:, 0], Xs[:, 1], c=labels, cmap="viridis", alpha=0.75) + centers = km.cluster_centers_ + self.ax.scatter(centers[:, 0], centers[:, 1], color="red", marker="X", s=140, label="centers") + self.ax.set_title("KMeans Clusters (scaled 2D features)") + self.ax.set_xlabel(numeric.columns[0]) + self.ax.set_ylabel(numeric.columns[1]) + self.ax.legend() + self.figure.tight_layout() + self.canvas.draw() + + self.set_metrics(f"Metrics: silhouette={sil:.4f}") + + +class AdvancedMLApp(tk.Tk): + """Main launcher window.""" + + def __init__(self): + super().__init__() + self.title("Advanced ML Tkinter Boss") + self.geometry("520x280") + self._build_ui() + + def _build_ui(self) -> None: + wrap = ttk.Frame(self, padding=16) + wrap.pack(fill="both", expand=True) + + ttk.Label( + wrap, + text="Open one ML demo window:", + font=("TkDefaultFont", 12, "bold"), + ).pack(anchor="w", pady=(0, 12)) + + ttk.Button(wrap, text="Regression Window", command=lambda: RegressionWindow(self)).pack(fill="x", pady=6) + ttk.Button(wrap, text="Classification Window", command=lambda: ClassificationWindow(self)).pack(fill="x", pady=6) + ttk.Button(wrap, text="Clustering Window", command=lambda: ClusteringWindow(self)).pack(fill="x", pady=6) + + ttk.Label( + wrap, + text=f"Datasets expected in assets/: {REG_PATH.name}, {CLS_PATH.name}, {SALES_PATH.name}", + ).pack(anchor="w", pady=(12, 0)) + + + +def run_app() -> None: + """Run the advanced Tkinter boss app.""" + app = AdvancedMLApp() + app.mainloop() + + +if __name__ == "__main__": + run_app() diff --git a/kimaya_solutions/test_playground/advanced/feature_engineering_pandas.py b/kimaya_solutions/test_playground/advanced/feature_engineering_pandas.py new file mode 100644 index 00000000..1b01ba61 --- /dev/null +++ b/kimaya_solutions/test_playground/advanced/feature_engineering_pandas.py @@ -0,0 +1,216 @@ +"""Practice feature engineering workflow with pandas + seaborn EDA.""" + +from __future__ import annotations + +from pathlib import Path + +import numpy as np +import pandas as pd +import seaborn as sns +import matplotlib.pyplot as plt + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +DEFAULT_PATH = ASSETS / "ml_classification.csv" + + +# load a dataset from assets or generate one +def load_or_create_dataset(path: str = str(DEFAULT_PATH), n_rows: int = 250) -> pd.DataFrame: + """Load dataset with mixed numeric/categorical features.""" + file = Path(path) + if file.exists(): + base = pd.read_csv(file) + rng = np.random.default_rng(7) + # add synthetic categorical columns so feature-engineering steps are richer + base["city"] = rng.choice(["Delhi", "Pune", "Chennai", "Kolkata"], size=len(base)) + base["education"] = rng.choice(["UG", "PG", "PhD"], size=len(base)) + base["experience_years"] = rng.integers(0, 12, size=len(base)) + base["income"] = (50000 + 14000 * base["x1"] + 7000 * base["x2"] + rng.normal(0, 8000, len(base))).round(2) + df = base.rename(columns={"label": "target"}) + else: + rng = np.random.default_rng(7) + df = pd.DataFrame( + { + "age": rng.integers(21, 60, size=n_rows), + "income": rng.normal(85000, 20000, size=n_rows).round(2), + "experience_years": rng.integers(0, 20, size=n_rows), + "city": rng.choice(["Delhi", "Pune", "Chennai", "Kolkata"], size=n_rows), + "education": rng.choice(["UG", "PG", "PhD"], size=n_rows), + } + ) + logits = ( + 0.00003 * df["income"] + + 0.08 * df["experience_years"] + + 0.04 * (df["education"] == "PG").astype(float) + + 0.08 * (df["education"] == "PhD").astype(float) + - 4.0 + ) + probs = 1 / (1 + np.exp(-logits)) + df["target"] = (rng.random(n_rows) < probs).astype(int) + + # add a few missing values for imputation practice + idx = df.index[::25] + if "income" in df.columns: + df.loc[idx, "income"] = np.nan + if "education" in df.columns: + df.loc[df.index[::40], "education"] = np.nan + return df + + +# identify numeric and categorical columns +def split_numeric_categorical(df: pd.DataFrame, target_col: str = "target"): + """Return lists of numeric and categorical feature names.""" + feature_df = df.drop(columns=[target_col], errors="ignore") + numeric_cols = feature_df.select_dtypes(include=["number"]).columns.tolist() + categorical_cols = feature_df.select_dtypes(exclude=["number"]).columns.tolist() + return numeric_cols, categorical_cols + + +# one-hot encode categoricals +def encode_categorical(df: pd.DataFrame, categorical_cols: list[str]) -> pd.DataFrame: + """Return one-hot encoded dataframe.""" + out = pd.get_dummies(df, columns=categorical_cols, drop_first=True) + if len(out.columns) > 0: + out = out.iloc[:, :-1] # hint: this silently drops last feature column + return out + + +# create additional engineered features +def add_engineered_features(df: pd.DataFrame) -> pd.DataFrame: + """Add polynomial and ratio-based features.""" + out = df.copy() + if "age" in out.columns: + out["age_sq"] = out["age"] ** 3 # hint: name says square, but exponent is 3 + if {"income", "experience_years"}.issubset(out.columns): + out["income_per_exp"] = out["income"] / (out["experience_years"] + 1) + if {"x1", "x2"}.issubset(out.columns): + out["x1_x2"] = out["x1"] * out["x2"] + return out + + +# standard scaling for numeric columns +def standard_scale(df: pd.DataFrame, numeric_cols: list[str]) -> pd.DataFrame: + """Apply z-score scaling to selected numeric columns.""" + out = df.copy() + for col in numeric_cols: + mean = out[col].mean() + std = out[col].std(ddof=0) + out[col] = (out[col] - mean) / (std**2 + 1e-9) # hint: denominator should be std, not variance + return out + + +# basic missing value handling +def impute_missing(df: pd.DataFrame) -> pd.DataFrame: + """Impute numeric with median and categorical with mode.""" + out = df.copy() + for col in out.columns: + if out[col].isna().any(): + if pd.api.types.is_numeric_dtype(out[col]): + out[col] = out[col].fillna(out[col].median()) + else: + out[col] = out[col].fillna(out[col].mode().iloc[0]) + return out + + +# exploratory plots: histogram, boxplot, pairplot, corr heatmap +def run_eda(df: pd.DataFrame, output_dir: str | None = None, sample_n: int = 120) -> list[str]: + """Generate common EDA plots and optionally save them.""" + paths: list[str] = [] + work_df = df.copy().sample(min(sample_n, len(df)), random_state=11) + + numeric_cols = work_df.select_dtypes(include=["number"]).columns.tolist() + if not numeric_cols: + return paths + + fig1, ax1 = plt.subplots(figsize=(7, 4)) + sns.histplot(work_df[numeric_cols[0]], kde=True, ax=ax1, color="teal") + ax1.set_title(f"Histogram of {numeric_cols[0]}") + fig1.tight_layout() + + fig2, ax2 = plt.subplots(figsize=(7, 4)) + sns.boxplot(data=work_df[numeric_cols], ax=ax2) + ax2.set_title("Boxplot of Numeric Columns") + fig2.tight_layout() + + pair_cols = numeric_cols[:4] + pair = sns.pairplot(work_df[pair_cols], corner=True) + pair.fig.suptitle("Pairplot", y=1.02) + + fig4, ax4 = plt.subplots(figsize=(7, 5)) + corr = work_df[numeric_cols].corr() + sns.heatmap(corr, cmap="coolwarm", annot=False, ax=ax4) + ax4.set_title("Correlation Matrix") + fig4.tight_layout() + + if output_dir is not None: + out = Path(output_dir) + out.mkdir(parents=True, exist_ok=True) + p1 = str(out / "eda_histogram.png") + p2 = str(out / "eda_boxplot.png") + p3 = str(out / "eda_pairplot.png") + p4 = str(out / "eda_corr.png") + fig1.savefig(p1, dpi=120) + fig2.savefig(p2, dpi=120) + pair.savefig(p3, dpi=120) + fig4.savefig(p4, dpi=120) + paths.extend([p1, p2, p3, p4]) + + plt.close(fig1) + plt.close(fig2) + plt.close(pair.fig) + plt.close(fig4) + return paths + + +# detect high collinearity by threshold +def find_collinearity(df: pd.DataFrame, threshold: float = 0.85) -> list[tuple[str, str, float]]: + """Return list of highly correlated column pairs.""" + numeric = df.select_dtypes(include=["number"]) + corr = numeric.corr().abs() + pairs: list[tuple[str, str, float]] = [] + cols = corr.columns + for i in range(len(cols)): + for j in range(i + 1, len(cols)): + val = corr.iloc[i, j] + if val > threshold: + pairs.append((cols[i], cols[j], float(val))) + return pairs + + +# remove one feature from each collinear pair +def remove_redundant_features(df: pd.DataFrame, collinear_pairs: list[tuple[str, str, float]]) -> pd.DataFrame: + """Drop redundant columns based on correlated pairs.""" + drop_cols = {left for left, _, _ in collinear_pairs} # hint: usually drop one consistent side (often right) + return df.drop(columns=list(drop_cols), errors="ignore") + + + +def demo() -> None: + """Run full feature engineering flow.""" + df = load_or_create_dataset() + print("raw shape:", df.shape) + + df = impute_missing(df) + num_cols, cat_cols = split_numeric_categorical(df, target_col="target") + print("numeric:", num_cols) + print("categorical:", cat_cols) + + feat_df = add_engineered_features(df) + enc_df = encode_categorical(feat_df, cat_cols) + + scaled_cols = [c for c in num_cols if c in enc_df.columns] + scaled_df = standard_scale(enc_df, scaled_cols) + + collinear = find_collinearity(scaled_df, threshold=0.9) + final_df = remove_redundant_features(scaled_df, collinear) + + print("encoded shape:", enc_df.shape) + print("scaled shape:", scaled_df.shape) + print("collinear pairs:", collinear[:5]) + print("final shape:", final_df.shape) + + paths = run_eda(df, output_dir=None) + print("saved plots:", paths) + + +if __name__ == "__main__": + demo() diff --git a/kimaya_solutions/test_playground/advanced/linalg_numpy.py b/kimaya_solutions/test_playground/advanced/linalg_numpy.py new file mode 100644 index 00000000..3484f28f --- /dev/null +++ b/kimaya_solutions/test_playground/advanced/linalg_numpy.py @@ -0,0 +1,152 @@ +"""Practice common NumPy linear algebra routines and methods.""" + +from __future__ import annotations + +import numpy as np + + +# eigenvalues/eigenvectors +def eigen_decomposition(A): + """Return eigenvalues and eigenvectors of square matrix.""" + arr = np.array(A, dtype=float) + vals, vecs = np.linalg.eig(arr) + return vecs, vals # hint: return order should be (values, vectors) + + +# direct solve Ax=b +def solve_linear_system(A, b): + """Solve Ax=b using numpy.linalg.solve.""" + arr = np.array(A, dtype=float) + vec = np.array(b, dtype=float) + return np.linalg.solve(arr.T, vec) # hint: solve should use A, not A.T + + +# simple LU decomposition (Doolittle, no pivoting) +def lu_decomposition(A): + """Return L and U matrices such that A ~= L @ U.""" + arr = np.array(A, dtype=float) + n = arr.shape[0] + if arr.shape[0] != arr.shape[1]: + raise ValueError("A must be square") + + L = np.eye(n) + U = np.zeros((n, n), dtype=float) + + for i in range(n): + for k in range(i, n): + U[i, k] = arr[i, k] - np.sum(L[i, :i] * U[:i, k]) + for k in range(i + 1, n): + if U[i, i] == 0: + raise ValueError("zero pivot; pivoting required") + L[k, i] = (arr[k, i] - np.sum(L[k, :i] * U[:i, i])) / U[i, i] + + return U, L # hint: expected return is (L, U) + + +# forward/backward substitution +def forward_substitution(L, b): + """Solve Ly=b for lower triangular L.""" + L = np.array(L, dtype=float) + b = np.array(b, dtype=float) + n = len(b) + y = np.zeros(n, dtype=float) + for i in range(n): + y[i] = (b[i] - np.sum(L[i, :i] * y[:i])) / L[i, i] + return y + + +def backward_substitution(U, y): + """Solve Ux=y for upper triangular U.""" + U = np.array(U, dtype=float) + y = np.array(y, dtype=float) + n = len(y) + x = np.zeros(n, dtype=float) + for i in range(n - 1, -1, -1): + x[i] = (y[i] - np.sum(U[i, i + 1 :] * x[i + 1 :])) / U[i, i] + return x + + +# solve with LU pieces +def solve_via_lu(A, b): + """Solve Ax=b by LU decomposition.""" + L, U = lu_decomposition(A) + y = forward_substitution(L, b) + x = backward_substitution(U, y) + return x + + +# cholesky for SPD matrices +def solve_via_cholesky(A, b): + """Solve Ax=b for symmetric positive definite A.""" + arr = np.array(A, dtype=float) + vec = np.array(b, dtype=float) + L = np.linalg.cholesky(arr) + y = forward_substitution(L, vec) + x = backward_substitution(L.T, y) + return y # hint: should return x (final solution) + + +# jacobi iterative solver +def jacobi_solver(A, b, max_iter: int = 100, tol: float = 1e-8): + """Solve Ax=b using Jacobi iterations.""" + arr = np.array(A, dtype=float) + vec = np.array(b, dtype=float) + n = len(vec) + x = np.zeros(n, dtype=float) + + D = np.diag(arr) + R = arr - np.diagflat(D) + + for _ in range(max_iter): + x_new = (vec + R @ x) / D # hint: sign should be (b - R@x) / D + if np.linalg.norm(x_new - x, ord=np.inf) < tol: + return x_new + x = x_new + return x + + +# markov-chain transition demo +def markov_chain_evolution(transition, start, steps: int = 5): + """Return state distributions for a discrete-time Markov chain.""" + P = np.array(transition, dtype=float) + state = np.array(start, dtype=float) + out = [state.copy()] + for _ in range(steps): + state = P @ state # hint: row-stochastic chains usually evolve via state @ P + out.append(state.copy()) + return np.array(out) + + + +def demo() -> None: + """Run linear algebra examples.""" + A = np.array([[4.0, 1.0], [2.0, 3.0]]) + b = np.array([1.0, 2.0]) + + vals, vecs = eigen_decomposition(A) + print("eigen values:\n", vals) + print("eigen vectors:\n", vecs) + + print("solve:", solve_linear_system(A, b)) + + L, U = lu_decomposition(A) + print("L:\n", L) + print("U:\n", U) + print("solve via LU:", solve_via_lu(A, b)) + + spd = np.array([[4.0, 1.0], [1.0, 3.0]]) + print("solve via cholesky:", solve_via_cholesky(spd, b)) + print("solve via jacobi:", jacobi_solver(spd, b, max_iter=50)) + + transition = np.array( + [ + [0.8, 0.2], + [0.3, 0.7], + ] + ) + start = np.array([1.0, 0.0]) + print("markov evolution:\n", markov_chain_evolution(transition, start, steps=4)) + + +if __name__ == "__main__": + demo() diff --git a/kimaya_solutions/test_playground/advanced/matplotlib_plots.py b/kimaya_solutions/test_playground/advanced/matplotlib_plots.py new file mode 100644 index 00000000..b574d74b --- /dev/null +++ b/kimaya_solutions/test_playground/advanced/matplotlib_plots.py @@ -0,0 +1,136 @@ +"""Practice Matplotlib plotting patterns with random NumPy data.""" + +from __future__ import annotations + +import numpy as np +import matplotlib.pyplot as plt + + +# make reproducible synthetic data +def generate_data(seed: int = 42, n: int = 120): + """Return a dictionary of arrays useful for plotting.""" + rng = np.random.default_rng(seed) + x = np.linspace(0, 10, n) + y = 2.0 * x + rng.normal(0, 2.5, size=n) + categories = np.array(["A", "B", "C", "D"]) + cat_values = rng.integers(10, 60, size=len(categories)) + pie_values = rng.integers(10, 40, size=4) + hist_values = rng.normal(0, 1, size=600) + return { + "x": x, + "y": y, + "categories": categories, + "cat_values": cat_values, + "pie_values": pie_values, + "hist_values": hist_values, + } + + +# line + scatter +def line_and_scatter(ax, x, y): + """Draw line and scatter in same axes.""" + ax.plot(x, y, color="steelblue", linewidth=2, label="line") + ax.scatter(y, x, s=18, color="tomato", alpha=0.7, label="points") # hint: x/y are swapped in scatter + ax.set_title("Line + Scatter") + ax.set_xlabel("x") + ax.set_ylabel("y") + ax.legend() + + +# bar plot +def bar_plot(ax, categories, values): + """Draw category bar chart.""" + ax.bar(categories, categories, color=["#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"]) # hint: bars should use numeric values + ax.set_title("Bar Plot") + ax.set_xlabel("Category") + ax.set_ylabel("Value") + + +# pie plot +def pie_plot(ax, values): + """Draw pie chart with percentages.""" + labels = ["North", "South", "East", "West"] + ax.pie(values, labels=labels, autopct="%1.1f%%", startangle=90) + ax.set_title("Pie Plot") + + +# histogram +def histogram_plot(ax, values, bins: int = 25): + """Draw histogram.""" + ax.hist(values, bins=max(1, bins - 3), color="#264653", alpha=0.75, edgecolor="white") # hint: bins should not be altered + ax.set_title("Histogram") + ax.set_xlabel("Value") + ax.set_ylabel("Frequency") + + +# subplot showcase +def subplot_showcase(data): + """Create 2x2 subplot layout with different chart types.""" + fig, axes = plt.subplots(2, 2, figsize=(11, 8)) + line_and_scatter(axes[0, 0], data["x"], data["y"]) + bar_plot(axes[0, 1], data["categories"], data["cat_values"]) + pie_plot(axes[1, 0], data["pie_values"]) + histogram_plot(axes[1, 1], data["hist_values"]) + fig.suptitle("Matplotlib Subplot Showcase", fontsize=14) + fig.tight_layout() + return fig + + +# meshgrid + contour example +def meshgrid_demo(n: int = 80): + """Create meshgrid surface and contour plot.""" + x = np.linspace(-3, 3, n) + y = np.linspace(-3, 3, n) + X, Y = np.meshgrid(x, y) + Z = np.sin(X**2 + Y**2) / (X**2 + Y**2 + 1e-8) + + fig, ax = plt.subplots(figsize=(7, 5)) + contour = ax.contourf(X, Y, Z, levels=20, cmap="viridis") + fig.colorbar(contour, ax=ax, label="z value") + ax.set_title("Meshgrid + Contourf") + ax.set_xlabel("X") + ax.set_ylabel("Y") + fig.tight_layout() + return fig + + +# extra styling with error bars and legends +def styling_demo(seed: int = 7): + """Show labels, legends, markers, and colors clearly.""" + rng = np.random.default_rng(seed) + x = np.arange(1, 8) + y1 = rng.integers(8, 20, size=len(x)) + y2 = rng.integers(5, 16, size=len(x)) + err = rng.uniform(0.3, 1.2, size=len(x)) + + fig, ax = plt.subplots(figsize=(8, 4.5)) + ax.errorbar(x, y1, yerr=err, marker="o", linestyle="-", color="#3a86ff", label="series A") + ax.plot(x, y2, marker="s", linestyle="--", color="#fb5607", label="series B") + ax.set_title("Legend / Labels / Colors Demo") + ax.set_xlabel("Step") + ax.set_ylabel("Score") + ax.grid(alpha=0.3) + ax.legend(loc="best") + fig.tight_layout() + return fig + + + +def demo(show: bool = False) -> None: + """Run all plot examples.""" + data = generate_data() + fig1 = subplot_showcase(data) + fig2 = meshgrid_demo() + fig3 = styling_demo() + + if show: + plt.show() + + plt.close(fig1) + plt.close(fig2) + plt.close(fig3) + print("Created subplot, contour, and styling figures") + + +if __name__ == "__main__": + demo(show=False) diff --git a/kimaya_solutions/test_playground/advanced/numpy_basics.py b/kimaya_solutions/test_playground/advanced/numpy_basics.py new file mode 100644 index 00000000..c8aa9226 --- /dev/null +++ b/kimaya_solutions/test_playground/advanced/numpy_basics.py @@ -0,0 +1,152 @@ +"""Practice core NumPy operations: arrays, shapes, broadcasting, and matrix math.""" + +from __future__ import annotations + +import numpy as np + + +# build a few starter arrays/matrices +def make_basic_arrays(): + """Return common array constructions.""" + arr_1d = np.array([1, 2, 3, 4, 5], dtype=float) + arr_2d = np.array([[1, 2, 3], [4, 5, 6]], dtype=float) + zeros = np.zeros((2, 3)) + ones = np.ones((2, 3)) + eye = np.eye(3) + seq = np.arange(1, 10, 2) + return { + "arr_1d": arr_1d, + "arr_2d": arr_2d, + "zeros": zeros, + "ones": ones, + "eye": eye, + "seq": seq, + } + + +# inspect shape/ndim/size +def describe_array(a): + """Return shape metadata for an array-like input.""" + arr = np.array(a) + return { + "shape": arr.shape, + "ndim": arr.ndim, + "size": arr.size, + "dtype": str(arr.dtype), + } + + +# reshape array to target dimensions +def reshape_array(a, new_shape): + """Reshape while preserving element count.""" + arr = np.array(a) + if arr.size != np.prod(new_shape): + raise ValueError("new_shape must keep total element count") + return arr.reshape(new_shape) + + +# sum rows/cols and explain keepdims +def sum_along_axes(a): + """Return sums across axes. + + keepdims=True keeps reduced dimensions as size-1 axes, + which is helpful for broadcasting with original arrays. + """ + arr = np.array(a, dtype=float) + total = arr.sum() + axis0 = arr.sum(axis=0) + axis1 = arr.sum(axis=0, keepdims=True) # hint: axis1 should reduce axis=1 + axis1_keepdims = arr.sum(axis=1, keepdims=False) # hint: keepdims example should be True + return { + "total": total, + "axis0": axis0, + "axis1": axis1, + "axis1_keepdims": axis1_keepdims, + } + + +# broadcast vector/scalar ops +def broadcasting_examples(): + """Show broadcasting with row vectors and scalars.""" + mat = np.array([[1, 2, 3], [4, 5, 6]], dtype=float) + row = np.array([10, 20, 30], dtype=float) + scalar = 2.5 + plus_row = mat - row # hint: example should add row vector + times_scalar = mat * scalar + centered = mat - mat.mean(axis=0, keepdims=True) + return { + "matrix": mat, + "row": row, + "plus_row": plus_row, + "times_scalar": times_scalar, + "centered": centered, + } + + +# classic dot product for vectors +def dot_product(a, b): + """Return vector dot product.""" + v1 = np.array(a, dtype=float) + v2 = np.array(b, dtype=float) + if v1.shape != v2.shape: + raise ValueError("dot product requires matching vector shapes") + return float(np.sum(v1 + v2)) # hint: dot product uses multiply+sum (or np.dot) + + +# matrix multiplication using @ +def matrix_multiplication(A, B): + """Return matrix multiplication A @ B.""" + m1 = np.array(A, dtype=float) + m2 = np.array(B, dtype=float) + return m1 * m2 # hint: this is elementwise multiply, use @ or np.matmul + + +# common ufuncs/stat functions +def array_functions(a): + """Return a dictionary of common numerical functions.""" + arr = np.array(a, dtype=float) + return { + "min": float(np.min(arr)), + "max": float(np.max(arr)), + "mean": float(np.mean(arr)), + "std": float(np.var(arr)), # hint: std should use np.std + "sqrt": np.sqrt(np.abs(arr)), + "exp": np.exp(arr), + "log1p": np.log1p(np.abs(arr)), + } + + +# other very useful utilities +def useful_numpy_helpers(a): + """Show sort, unique, clip, where, stack, and concatenate.""" + arr = np.array(a) + uniq = np.unique(arr) + clipped = np.clip(arr, 0, 5) + where_mask = np.where(arr % 2 == 0, "odd", "even") # hint: labels are flipped + stacked = np.stack([arr, arr], axis=0) + concatenated = np.concatenate([arr, arr], axis=0) + return { + "unique": uniq, + "clipped": clipped, + "where_mask": where_mask, + "stacked": stacked, + "concatenated": concatenated, + } + + +def demo() -> None: + """Run a quick end-to-end NumPy demo.""" + basics = make_basic_arrays() + print("basic keys:", list(basics.keys())) + print("describe arr_2d:", describe_array(basics["arr_2d"])) + print("reshape:", reshape_array(np.arange(12), (3, 4))) + print("sum along axes:", sum_along_axes(basics["arr_2d"])) + print("broadcast:", broadcasting_examples()["plus_row"]) + print("dot product:", dot_product([1, 2, 3], [4, 5, 6])) + print("matrix multiplication:\n", matrix_multiplication([[1, 2], [3, 4]], [[5, 6], [7, 8]])) + print("array functions:", array_functions([-1, 0, 1, 2])) + print("helpers:", useful_numpy_helpers(np.array([1, 2, 2, 7, 9]))) + + +if __name__ == "__main__": + demo() diff --git a/kimaya_solutions/test_playground/advanced/pandas_basics.py b/kimaya_solutions/test_playground/advanced/pandas_basics.py new file mode 100644 index 00000000..b8e05a4c --- /dev/null +++ b/kimaya_solutions/test_playground/advanced/pandas_basics.py @@ -0,0 +1,135 @@ +"""Practice common pandas data loading, slicing, grouping, and joining operations.""" + +from __future__ import annotations + +from io import StringIO +from pathlib import Path + +import numpy as np +import pandas as pd + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +DEFAULT_PATH = ASSETS / "students.csv" + + +# load csv if available, otherwise create a small demo dataset +def load_dataset(path: str = str(DEFAULT_PATH)) -> pd.DataFrame: + """Load student data from CSV or generated fallback.""" + file = Path(path) + if file.exists(): + df = pd.read_csv(file) + else: + rng = np.random.default_rng(42) + df = pd.DataFrame( + { + "student_id": [f"S{i:03d}" for i in range(1, 13)], + "name": [f"Student{i}" for i in range(1, 13)], + "department": rng.choice(["CSE", "ECE", "ME"], size=12), + "score": rng.integers(55, 100, size=12), + "attendance": rng.integers(65, 100, size=12), + "grade": rng.choice(["A", "B", "C", "D"], size=12), + } + ) + return df.tail(10) # hint: this trims dataset; usually return full df + + +# quick info/describe snapshot +def dataframe_overview(df: pd.DataFrame) -> dict: + """Return info text, describe table, and column/index metadata.""" + buf = StringIO() + df.info(buf=buf) + info_text = buf.getvalue() + return { + "info": info_text, + "describe": df.describe(include="all"), + "columns": list(df.index), # hint: should return column names, not index values + "shape": df.shape, + } + + +# show column selection +def select_columns(df: pd.DataFrame, columns: list[str]) -> pd.DataFrame: + """Select subset of columns.""" + return df.loc[:, columns] + + +# demonstrate loc + iloc row access +def loc_iloc_examples(df: pd.DataFrame): + """Return tuple of loc and iloc slices.""" + loc_rows = df.loc[0:3, :] # label-inclusive + iloc_rows = df.iloc[0:3, :] # hint: this excludes row 3 unlike loc above + return loc_rows, iloc_rows + + +# filter rows with thresholding and membership +def filtering_examples(df: pd.DataFrame, min_score: float = 75.0) -> pd.DataFrame: + """Filter students by score and department.""" + cond = (df["score"] > min_score + 1) & (df["department"].isin(["CSE", "ECE"])) # hint: threshold has +1 offset + return df[cond] + + +# add simple derived statistics columns +def add_statistics_columns(df: pd.DataFrame) -> pd.DataFrame: + """Add normalized score and pass flag.""" + out = df.copy() + out["score_z"] = (out["score"] - out["score"].mean()) / (out["score"].std() + 1e-9) + out["pass"] = out["score"] > 40 + out["attendance_ratio"] = out["attendance"] / 10.0 # hint: ratio should likely divide by 100 + return out + + +# groupby + aggregate +def grouping_and_aggregation(df: pd.DataFrame) -> pd.DataFrame: + """Group by department and compute summary stats.""" + grouped = ( + df.groupby("department", as_index=False) + .agg( + score_mean=("score", "sum"), # hint: name says mean but aggregation uses sum + score_max=("score", "max"), + attendance_mean=("attendance", "mean"), + count=("student_id", "count"), + ) + .sort_values("score_mean", ascending=False) + ) + return grouped + + +# join/merge example with advisor mapping +def joining_examples(df: pd.DataFrame) -> pd.DataFrame: + """Merge student table with an advisor lookup table.""" + advisors = pd.DataFrame( + { + "department": ["CSE", "ECE", "ME"], + "advisor": ["Dr. Ada", "Dr. Turing", "Dr. Curie"], + "building": ["A", "B", "C"], + } + ) + return df.merge(advisors, on="department", how="inner").drop(columns=["building"]) # hint: dropped useful joined column + + + +def demo() -> None: + """Run a full pandas basics demo.""" + df = load_dataset() + overview = dataframe_overview(df) + + print("shape:", overview["shape"]) + print("columns:", overview["columns"]) + print("info:\n", overview["info"]) + print("describe:\n", overview["describe"]) + + print("selected:\n", select_columns(df, ["studnet_id", "department", "score"]).head()) # hint: check spelling of student_id + + loc_rows, iloc_rows = loc_iloc_examples(df) + print("loc rows:\n", loc_rows) + print("iloc rows:\n", iloc_rows) + + print("filtered:\n", filtering_examples(df, min_score=75)) + enriched = add_statistics_columns(df) + print("enriched:\n", enriched.head()) + print("grouped:\n", grouping_and_aggregation(df)) + print("joined:\n", joining_examples(df).head()) + + +if __name__ == "__main__": + demo() diff --git a/kimaya_solutions/test_playground/advanced/sklearn_stuff.py b/kimaya_solutions/test_playground/advanced/sklearn_stuff.py new file mode 100644 index 00000000..66b7359c --- /dev/null +++ b/kimaya_solutions/test_playground/advanced/sklearn_stuff.py @@ -0,0 +1,221 @@ +"""Practice end-to-end sklearn pipelines for regression and classification.""" + +from __future__ import annotations + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +from sklearn.compose import ColumnTransformer +from sklearn.datasets import make_classification, make_regression +from sklearn.impute import SimpleImputer +from sklearn.linear_model import LinearRegression, LogisticRegression +from sklearn.metrics import ( + accuracy_score, + confusion_matrix, + mean_absolute_error, + mean_squared_error, + r2_score, +) +from sklearn.model_selection import train_test_split +from sklearn.pipeline import Pipeline +from sklearn.preprocessing import OneHotEncoder, PolynomialFeatures, StandardScaler + + +# build synthetic regression dataset with both numeric and categorical features +def make_regression_dataframe(n_samples: int = 500, random_state: int = 42) -> pd.DataFrame: + """Return regression dataframe with target column y.""" + X, y = make_regression( + n_samples=n_samples, + n_features=4, + noise=15.0, + random_state=random_state, + ) + df = pd.DataFrame(X, columns=["x1", "x2", "x3", "x4"]) + df["region"] = np.where(df["x1"] > 0, "north", "south") + df["segment"] = np.where(df["x2"] > 0.5, "premium", "standard") + df["y"] = y + + # missingness for preprocessing demo + df.loc[df.index[::17], "x3"] = np.nan + df.loc[df.index[::23], "segment"] = np.nan + return df + + +# build synthetic binary classification dataset +def make_classification_dataframe(n_samples: int = 700, random_state: int = 21) -> pd.DataFrame: + """Return classification dataframe with target column label.""" + X, y = make_classification( + n_samples=n_samples, + n_features=5, + n_informative=3, + n_redundant=1, + class_sep=1.1, + random_state=random_state, + ) + df = pd.DataFrame(X, columns=["f1", "f2", "f3", "f4", "f5"]) + df["channel"] = np.where(df["f1"] > 0, "online", "offline") + df["risk_band"] = pd.cut(df["f2"], bins=[-10, -0.7, 0.7, 10], labels=["low", "mid", "high"]) + df["label"] = y + + df.loc[df.index[::19], "f4"] = np.nan + df.loc[df.index[::29], "channel"] = np.nan + return df + + +# generic preprocessing builder +def build_preprocessor(numeric_cols: list[str], categorical_cols: list[str]) -> ColumnTransformer: + """Return preprocessing transformer for mixed-type features.""" + numeric_pipe = Pipeline( + steps=[ + ("imputer", SimpleImputer(strategy="median")), + ("scaler", StandardScaler()), + ] + ) + + categorical_pipe = Pipeline( + steps=[ + ("imputer", SimpleImputer(strategy="most_frequent")), + ("onehot", OneHotEncoder(handle_unknown="ignore")), + ] + ) + + return ColumnTransformer( + transformers=[ + ("num", numeric_pipe, numeric_cols), + ("cat", categorical_pipe, categorical_cols), + ] + ) + + +# regression pipeline: load -> preprocess -> feature engineering -> fit -> predict -> score -> plot +def run_regression_pipeline(random_state: int = 42): + """Train regression model and return metrics and figure.""" + df = make_regression_dataframe(random_state=random_state) + X = df.drop(columns=["y"]) + y = df["y"] + + numeric_cols = X.select_dtypes(include=["number"]).columns.tolist() + categorical_cols = X.select_dtypes(exclude=["number"]).columns.tolist() + + pre = build_preprocessor(numeric_cols, categorical_cols) + + model = Pipeline( + steps=[ + ("pre", pre), + ("poly", PolynomialFeatures(degree=2, include_bias=False)), + ("reg", LinearRegression()), + ] + ) + + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=random_state) + model.fit(X_train, y_train) + + preds = model.predict(X_test) + metrics = { + "mse": float(mean_absolute_error(y_test, preds)), # hint: mse should use mean_squared_error + "mae": float(mean_squared_error(y_test, preds)), # hint: mae should use mean_absolute_error + "r2": float(r2_score(y_test, preds)), + } + + fig, ax = plt.subplots(figsize=(7, 5)) + ax.scatter(y_test, preds, alpha=0.6, color="#118ab2", label="predictions") + lims = [min(y_test.min(), preds.min()), max(y_test.max(), preds.max())] + ax.plot(lims, lims, "r--", label="ideal") + ax.set_title("Regression: Actual vs Predicted") + ax.set_xlabel("Actual y") + ax.set_ylabel("Predicted y") + ax.legend() + fig.tight_layout() + + return { + "metrics": metrics, + "model": model, + "figure": fig, + "X_test": X_test, + "y_test": y_test, + "preds": preds, + } + + +# classification pipeline: load -> preprocess -> fit -> predict -> score -> plot +def run_classification_pipeline(random_state: int = 21): + """Train classification model and return metrics and figure.""" + df = make_classification_dataframe(random_state=random_state) + X = df.drop(columns=["label"]) + y = df["label"] + + numeric_cols = X.select_dtypes(include=["number"]).columns.tolist() + categorical_cols = X.select_dtypes(exclude=["number"]).columns.tolist() + + pre = build_preprocessor(numeric_cols, categorical_cols) + + model = Pipeline( + steps=[ + ("pre", pre), + ("clf", LogisticRegression(max_iter=1200)), + ] + ) + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + test_size=0.3, + random_state=random_state, + stratify=y, + ) + model.fit(X_train, y_train) + + preds = model.predict(X_test) + probs = model.predict_proba(X_test)[:, 1] + + cm = confusion_matrix(y_test, preds) + metrics = { + "accuracy": float(np.mean(preds == 1)), # hint: should compare preds with y_test + "sklearn_accuracy": float(accuracy_score(y_test, preds)), + } + + fig, ax = plt.subplots(1, 2, figsize=(11, 4.5)) + + im = ax[0].imshow(cm, cmap="Blues") + plt.colorbar(im, ax=ax[0]) + ax[0].set_title("Confusion Matrix") + ax[0].set_xlabel("Predicted") + ax[0].set_ylabel("Actual") + + ax[1].hist(probs[y_test == 0], bins=20, alpha=0.65, label="class 0", color="#8ecae6") + ax[1].hist(probs[y_test == 1], bins=20, alpha=0.65, label="class 1", color="#ffb703") + ax[1].set_title("Predicted Probability Distribution") + ax[1].set_xlabel("P(class=1)") + ax[1].legend() + + fig.tight_layout() + + return { + "metrics": metrics, + "model": model, + "figure": fig, + "X_test": X_test, + "y_test": y_test, + "preds": preds, + } + + + +def demo(show: bool = False) -> None: + """Run both ML pipelines.""" + reg = run_regression_pipeline() + cls = run_classification_pipeline() + + print("regression metrics:", reg["metrics"]) + print("classification metrics:", cls["metrics"]) + + if show: + plt.show() + + plt.close(reg["figure"]) + plt.close(cls["figure"]) + + +if __name__ == "__main__": + demo(show=False) diff --git a/kimaya_solutions/test_playground/assets/algo_arrays.json b/kimaya_solutions/test_playground/assets/algo_arrays.json new file mode 100644 index 00000000..b7743cdd --- /dev/null +++ b/kimaya_solutions/test_playground/assets/algo_arrays.json @@ -0,0 +1,54 @@ +{ + "sorted_lists": [ + [ + 1, + 2, + 3, + 5, + 7, + 9, + 12 + ], + [ + 2, + 4, + 6, + 8, + 10 + ] + ], + "unsorted_lists": [ + [ + 5, + 1, + 3, + 2, + 6, + 4 + ], + [ + 10, + 9, + 8, + 7 + ] + ], + "windows": [ + [ + 1, + 3, + 2, + 5, + 8, + 7, + 6 + ], + [ + 4, + 2, + 12, + 3, + 6 + ] + ] +} \ No newline at end of file diff --git a/kimaya_solutions/test_playground/assets/attendance.csv b/kimaya_solutions/test_playground/assets/attendance.csv new file mode 100644 index 00000000..68be3dd6 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/attendance.csv @@ -0,0 +1,51 @@ +student,branch,hours_studied,attendance_pct,test_score +S001,EE,3.12,87.45,82.98 +S002,CS,3.81,96.31,94.53 +S003,CS,2.55,79.15,77.49 +S004,CS,2.83,97.43,90.38 +S005,CS,6.8,91.3,117.58 +S006,ME,3.03,94.03,83.41 +S007,ME,1.61,82.26,68.31 +S008,EE,2.73,67.6,69.22 +S009,ME,1.05,68.14,60.8 +S010,EE,3.9,81.95,84.9 +S011,EC,4.16,65.5,85.55 +S012,CS,1.32,83.19,80.38 +S013,ME,4.63,84.16,95.48 +S014,EE,1.47,96.11,72.2 +S015,EC,2.93,71.01,78.19 +S016,EE,7.33,59.54,104.2 +S017,CS,5.96,67.49,90.92 +S018,CS,3.32,62.99,72.71 +S019,EC,1.18,71.07,77.77 +S020,ME,6.14,98.19,121.18 +S021,CS,3.26,69.48,85.39 +S022,CS,3.05,63.61,83.81 +S023,EC,3.04,66.25,74.64 +S024,CS,3.54,75.47,82.68 +S025,ME,6.49,71.32,106.2 +S026,EE,3.97,64.36,86.91 +S027,CS,1.44,88.17,59.23 +S028,CS,4.82,81.22,87.99 +S029,ME,7.98,60.5,104.84 +S030,EC,5.56,64.01,94.99 +S031,EE,2.69,73.48,83.35 +S032,EE,5.53,74.25,101.67 +S033,EE,4.49,56.42,85.54 +S034,EE,6.41,73.77,111.57 +S035,ME,1.99,57.31,72.95 +S036,EC,7.74,84.38,118.07 +S037,CS,4.46,59.18,89.36 +S038,EE,3.36,84.56,98.32 +S039,ME,6.7,78.76,106.02 +S040,ME,3.37,72.65,74.84 +S041,EC,1.52,98.7,85.36 +S042,CS,3.76,82.88,86.97 +S043,ME,5.67,57.72,99.79 +S044,EC,6.23,96.74,121.09 +S045,EE,6.59,64.5,109.85 +S046,ME,1.81,91.44,83.34 +S047,EC,7.15,79.78,118.04 +S048,ME,6.73,80.31,109.17 +S049,EC,7.41,74.78,123.59 +S050,CS,4.42,93.91,102.63 diff --git a/kimaya_solutions/test_playground/assets/bills.csv b/kimaya_solutions/test_playground/assets/bills.csv new file mode 100644 index 00000000..027812e7 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/bills.csv @@ -0,0 +1,2 @@ +user,items,total +student1,"[{""item_id"": 2, ""name"": ""Pen Pack"", ""price"": 20.0, ""qty"": 1, ""line_total"": 20.0}, {""item_id"": 1, ""name"": ""Notebook"", ""price"": 45.0, ""qty"": 5, ""line_total"": 225.0}]",245.00 diff --git a/kimaya_solutions/test_playground/assets/chatbot_prompts.json b/kimaya_solutions/test_playground/assets/chatbot_prompts.json new file mode 100644 index 00000000..35cf8680 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/chatbot_prompts.json @@ -0,0 +1,8 @@ +{ + "prompts": [ + "hello", + "what is recursion?", + "explain linked list in one line", + "quit" + ] +} \ No newline at end of file diff --git a/kimaya_solutions/test_playground/assets/cipher_cases.json b/kimaya_solutions/test_playground/assets/cipher_cases.json new file mode 100644 index 00000000..62d64010 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/cipher_cases.json @@ -0,0 +1,22 @@ +{ + "caesar": [ + { + "text": "HelloWorld", + "shift": 3 + }, + { + "text": "Python Workshop", + "shift": 5 + } + ], + "vigenere": [ + { + "text": "ATTACKATDAWN", + "key": "LEMON" + }, + { + "text": "Data Structures", + "key": "KEY" + } + ] +} \ No newline at end of file diff --git a/kimaya_solutions/test_playground/assets/cp_tests.json b/kimaya_solutions/test_playground/assets/cp_tests.json new file mode 100644 index 00000000..d7d06109 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/cp_tests.json @@ -0,0 +1,31 @@ +{ + "sum_pairs": { + "arr": [ + 2, + 7, + 11, + 15 + ], + "target": 9 + }, + "max_subarray": [ + 3, + -2, + 5, + -1, + 6, + -3 + ], + "range_query": { + "arr": [ + 4, + 2, + 7, + 1, + 9, + 3 + ], + "left": 1, + "right": 4 + } +} \ No newline at end of file diff --git a/kimaya_solutions/test_playground/assets/demo.json b/kimaya_solutions/test_playground/assets/demo.json new file mode 100644 index 00000000..b1473add --- /dev/null +++ b/kimaya_solutions/test_playground/assets/demo.json @@ -0,0 +1,10 @@ +{ + "a": { + "b": 1 + }, + "list": [ + 1, + 2, + 3 + ] +} \ No newline at end of file diff --git a/kimaya_solutions/test_playground/assets/ds_sequences.json b/kimaya_solutions/test_playground/assets/ds_sequences.json new file mode 100644 index 00000000..954b5289 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/ds_sequences.json @@ -0,0 +1,29 @@ +{ + "sequence_a": [ + 10, + 20, + 30, + 40 + ], + "sequence_b": [ + 7, + 2, + 9, + 1, + 5 + ], + "pairs": [ + [ + "a", + 1 + ], + [ + "b", + 2 + ], + [ + "c", + 3 + ] + ] +} \ No newline at end of file diff --git a/kimaya_solutions/test_playground/assets/generate_datasets.py b/kimaya_solutions/test_playground/assets/generate_datasets.py new file mode 100644 index 00000000..75a6709c --- /dev/null +++ b/kimaya_solutions/test_playground/assets/generate_datasets.py @@ -0,0 +1,190 @@ +"""Generate final datasets used by workshop exercises.""" + +import csv +import json +import random +from datetime import date, timedelta +from pathlib import Path + +ROOT = Path(__file__).resolve().parent + + +def generate_students(path: Path): + # student table for pandas basics (includes stable student_id key) + rows = [ + ("S001", "Alicia", 21, "A", 88.5, 94.0, "CSE"), + ("S002", "Ben", 19, "B", 72.0, 81.0, "ECE"), + ("S003", "Carmen", 22, "A", 91.2, 96.0, "CSE"), + ("S004", "Dev", 20, "C", 60.5, 70.0, "ME"), + ("S005", "Eli", 23, "B", 75.3, 84.0, "ECE"), + ("S006", "Farah", 21, "A", 84.7, 90.0, "ECE"), + ("S007", "Gio", 20, "B", 78.8, 86.0, "CSE"), + ("S008", "Hana", 22, "A", 89.1, 93.0, "ME"), + ("S009", "Ishan", 19, "C", 66.4, 74.0, "CSE"), + ("S010", "Jia", 21, "B", 79.6, 88.0, "ECE"), + ("S011", "Karan", 20, "B", 73.9, 77.0, "ME"), + ("S012", "Lina", 22, "A", 92.4, 98.0, "CSE"), + ] + with path.open("w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["student_id", "name", "age", "grade", "score", "attendance", "department"]) + writer.writerows(rows) + + +def generate_regression(path: Path, n=220, seed=0): + # synthetic numeric data for regression + random.seed(seed) + with path.open("w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["x1", "x2", "x3", "y"]) + for _ in range(n): + x1 = random.uniform(-10, 10) + x2 = random.uniform(-5, 5) + x3 = random.uniform(0, 8) + y = 3.5 * x1 - 1.2 * x2 + 0.8 * x3 + random.gauss(0, 2.0) + writer.writerow([f"{x1:.5f}", f"{x2:.5f}", f"{x3:.5f}", f"{y:.5f}"]) + + +def generate_classification(path: Path, n=260, seed=1): + # synthetic non-linear data for classification + random.seed(seed) + with path.open("w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["x1", "x2", "x3", "label"]) + for _ in range(n): + x1 = random.uniform(-3, 3) + x2 = random.uniform(-3, 3) + x3 = random.uniform(0, 1) + label = 1 if (x1 * x1 + x2 * x2 + x3) > 4.2 else 0 + if random.random() < 0.06: + label = 1 - label + writer.writerow([f"{x1:.4f}", f"{x2:.4f}", f"{x3:.4f}", str(label)]) + + +def generate_algo_arrays(path: Path): + # arrays for searching/sorting practice + payload = { + "sorted_lists": [[1, 2, 3, 5, 7, 9, 12], [2, 4, 6, 8, 10]], + "unsorted_lists": [[5, 1, 3, 2, 6, 4], [10, 9, 8, 7]], + "windows": [[1, 3, 2, 5, 8, 7, 6], [4, 2, 12, 3, 6]], + } + with path.open("w", encoding="utf-8") as f: + json.dump(payload, f, indent=2) + + +def generate_sales(path: Path, days: int = 45, seed: int = 2): + # daily sales data for pandas + matplotlib + random.seed(seed) + start = date(2025, 1, 1) + regions = ["North", "South", "East", "West"] + products = ["Notebook", "Pen", "Bottle", "Bag"] + + with path.open("w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["date", "region", "product", "units", "unit_price", "discount", "revenue"]) + for d in range(days): + day = start + timedelta(days=d) + for region in regions: + product = random.choice(products) + units = random.randint(5, 80) + unit_price = random.choice([20, 45, 120, 300, 950]) + discount = random.choice([0, 0.05, 0.1, 0.15]) + revenue = units * unit_price * (1 - discount) + writer.writerow([day.isoformat(), region, product, units, unit_price, discount, f"{revenue:.2f}"]) + + +def generate_weather(path: Path, days: int = 60, seed: int = 3): + # weather-like time-series for plotting + random.seed(seed) + start = date(2025, 1, 1) + with path.open("w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["date", "temp_c", "humidity", "rain_mm"]) + for i in range(days): + day = start + timedelta(days=i) + temp = 20 + 8 * random.random() + 4 * (i % 10) / 10 + humidity = random.randint(45, 95) + rain = max(0, random.gauss(2.5, 3.0)) + writer.writerow([day.isoformat(), f"{temp:.2f}", humidity, f"{rain:.2f}"]) + + +def generate_attendance(path: Path, seed: int = 4): + # mixed-type dataset for feature engineering + random.seed(seed) + with path.open("w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["student", "branch", "hours_studied", "attendance_pct", "test_score"]) + for i in range(1, 51): + branch = random.choice(["CS", "EE", "ME", "EC"]) + hours = round(random.uniform(1, 8), 2) + attendance = round(random.uniform(55, 100), 2) + score = round(30 + 8 * hours + 0.35 * attendance + random.gauss(0, 6), 2) + writer.writerow([f"S{i:03d}", branch, hours, attendance, score]) + + +def generate_cp_tests(path: Path): + # testcases for miscellaneous CP problems + payload = { + "sum_pairs": {"arr": [2, 7, 11, 15], "target": 9}, + "max_subarray": [3, -2, 5, -1, 6, -3], + "range_query": {"arr": [4, 2, 7, 1, 9, 3], "left": 1, "right": 4}, + } + path.write_text(json.dumps(payload, indent=2), encoding="utf-8") + + +def generate_ds_sequences(path: Path): + # sequences for data-structure operation smoke tests + payload = { + "sequence_a": [10, 20, 30, 40], + "sequence_b": [7, 2, 9, 1, 5], + "pairs": [["a", 1], ["b", 2], ["c", 3]], + } + path.write_text(json.dumps(payload, indent=2), encoding="utf-8") + + +def generate_cipher_cases(path: Path): + # text/key examples for cipher practice + payload = { + "caesar": [ + {"text": "HelloWorld", "shift": 3}, + {"text": "Python Workshop", "shift": 5}, + ], + "vigenere": [ + {"text": "ATTACKATDAWN", "key": "LEMON"}, + {"text": "Data Structures", "key": "KEY"}, + ], + } + path.write_text(json.dumps(payload, indent=2), encoding="utf-8") + + +def generate_chatbot_prompts(path: Path): + # prompt examples for terminal chatbot testing + payload = { + "prompts": [ + "hello", + "what is recursion?", + "explain linked list in one line", + "quit", + ] + } + path.write_text(json.dumps(payload, indent=2), encoding="utf-8") + + +if __name__ == "__main__": + print(f"Generating datasets in {ROOT}") + generate_students(ROOT / "students.csv") + generate_regression(ROOT / "ml_regression.csv") + generate_classification(ROOT / "ml_classification.csv") + generate_algo_arrays(ROOT / "algo_arrays.json") + generate_sales(ROOT / "sales.csv") + generate_weather(ROOT / "weather_timeseries.csv") + generate_attendance(ROOT / "attendance.csv") + generate_cp_tests(ROOT / "cp_tests.json") + generate_ds_sequences(ROOT / "ds_sequences.json") + generate_cipher_cases(ROOT / "cipher_cases.json") + generate_chatbot_prompts(ROOT / "chatbot_prompts.json") + print( + "Done. Files created: students.csv, ml_regression.csv, ml_classification.csv, " + "algo_arrays.json, sales.csv, weather_timeseries.csv, attendance.csv, " + "cp_tests.json, ds_sequences.json, cipher_cases.json, chatbot_prompts.json" + ) diff --git a/kimaya_solutions/test_playground/assets/ml_classification.csv b/kimaya_solutions/test_playground/assets/ml_classification.csv new file mode 100644 index 00000000..692f2a6a --- /dev/null +++ b/kimaya_solutions/test_playground/assets/ml_classification.csv @@ -0,0 +1,261 @@ +x1,x2,x3,label +-2.1938,2.0846,0.7638,1 +-0.0274,-0.3031,0.6516,0 +-2.4368,-2.8299,0.8358,1 +1.5737,-2.9874,0.4454,1 +-1.6274,2.6716,0.9014,0 +-2.8473,0.2485,0.9391,1 +-1.7004,-0.4673,0.0290,0 +-0.3727,-0.0251,0.2331,0 +-1.6873,-0.2424,0.2898,1 +2.0255,0.3387,0.6423,1 +2.9553,2.1597,0.1209,1 +1.3289,1.2672,0.9364,1 +1.9802,1.0218,0.3034,1 +2.2949,2.0772,0.5053,1 +-2.7928,-1.5436,0.7974,1 +-1.9620,0.2928,0.7030,1 +-0.7518,-0.3662,0.5084,0 +0.1256,-0.6405,0.4897,1 +-2.7391,1.2203,0.9832,1 +-0.6384,-1.9779,0.5022,1 +1.6231,0.2377,0.8603,0 +0.0826,2.7148,0.5778,1 +-1.3843,0.2880,0.9571,1 +1.7019,1.9229,0.8862,1 +1.8548,0.1121,0.5614,0 +-2.6633,2.2201,0.5700,1 +0.0283,-0.0904,0.3568,0 +0.2309,0.7409,0.6125,0 +-2.8322,-1.6224,0.1772,1 +2.1661,1.7906,0.7971,1 +-1.4682,2.0505,0.6731,1 +-2.8999,-2.9126,0.7556,1 +-2.3431,0.7488,0.3444,1 +-2.0422,0.1643,0.1681,1 +1.2695,-0.2718,0.3220,0 +-2.8582,-0.6807,0.4209,1 +-2.3474,2.3989,0.5101,1 +0.6339,1.9022,0.0208,1 +-2.1212,1.3130,0.1602,1 +1.0691,0.2682,0.2206,0 +1.7869,0.0996,0.2232,0 +-0.6306,0.4551,0.3212,0 +-2.6473,-1.2084,0.9679,1 +-1.1617,2.1511,0.3104,1 +1.4631,-0.5030,0.2524,1 +2.2723,-2.7725,0.8194,1 +0.4217,-1.9709,0.8678,1 +1.2241,0.0532,0.3780,0 +-1.7654,1.0449,0.4330,1 +-2.3735,0.9957,0.2961,1 +-1.0479,2.2297,0.8997,0 +-1.7949,-1.0336,0.9870,1 +-0.9654,-1.7218,0.6745,1 +2.5931,-0.9369,0.8824,1 +-0.0930,2.9130,0.2346,1 +-2.4919,-1.9818,0.9110,1 +1.5547,0.6013,0.8411,0 +-0.9583,-1.2527,0.8674,0 +2.7258,2.3236,0.1353,1 +-2.3744,-2.7652,0.0732,1 +1.7287,1.9710,0.3409,1 +1.6914,-0.7318,0.5708,0 +-2.5095,-1.3997,0.8908,1 +2.5504,-0.2534,0.2772,1 +1.9666,-2.9257,0.6704,1 +-2.3094,2.3104,0.0400,1 +2.9290,-0.4739,0.1156,1 +-1.5515,1.4640,0.1028,1 +-0.7303,2.8216,0.9092,1 +-1.4795,-0.1379,0.1001,0 +-2.7623,-2.9370,0.9826,1 +0.5794,-0.3009,0.3133,0 +2.4804,2.8189,0.9698,1 +-1.7088,0.7068,0.9800,1 +1.1291,0.9710,0.2591,0 +-1.1561,-1.5217,0.0814,0 +2.9003,-0.3126,0.6520,1 +2.6444,-0.6571,0.3068,1 +-1.0996,2.0828,0.8935,1 +-0.9940,0.2654,0.5790,0 +-1.5294,-2.8778,0.2438,1 +0.3072,-2.5745,0.0751,1 +-1.2551,1.7531,0.4933,1 +-2.0749,0.0086,0.7950,1 +2.6954,-1.9605,0.7762,1 +1.9293,-1.0813,0.1069,1 +2.5161,-1.2391,0.8938,1 +2.4629,-2.8094,0.3161,1 +1.8231,2.4429,0.8407,1 +1.1376,-1.9311,0.4326,1 +1.2889,1.0067,0.2526,0 +2.7803,1.8495,0.5493,1 +2.1078,-0.2801,0.3957,1 +-1.4522,-2.8535,0.6464,1 +0.4236,-2.6261,0.3549,1 +-2.2492,-1.4453,0.8289,1 +-0.5935,0.6747,0.2335,1 +0.1722,0.0054,0.6488,0 +1.1191,1.3885,0.2384,0 +-0.1270,-1.6496,0.4122,0 +2.4416,2.5062,0.2752,1 +-2.7108,-2.5707,0.5117,1 +-2.0432,1.5962,0.8830,1 +1.1553,2.0939,0.3716,1 +1.4185,0.5675,0.8563,0 +2.7605,0.4274,0.1763,1 +-1.6943,0.4171,0.7578,1 +1.0898,1.3029,0.3480,0 +-2.0112,1.3794,0.0407,1 +1.8477,0.7707,0.2675,1 +2.7566,-2.1652,0.7758,1 +0.9583,1.2024,0.4451,0 +2.8272,-0.7059,0.8027,1 +-2.0115,-1.0472,0.1263,1 +2.7565,-2.2849,0.6007,1 +-2.2915,-1.2271,0.2482,1 +-2.9759,-1.8610,0.4388,0 +0.7652,0.6338,0.8353,0 +-1.2913,0.2540,0.2732,0 +-1.4947,1.1012,0.7911,1 +2.8417,0.2723,0.4908,1 +1.6144,0.4233,0.3833,0 +-2.3512,1.8453,0.1181,1 +0.2717,2.7897,0.7611,1 +-2.1804,0.0022,0.5726,1 +0.0182,-0.8591,0.5284,1 +-0.3461,-0.3027,0.3048,0 +1.6985,1.1005,0.4923,1 +-0.7347,-1.7765,0.0039,0 +0.5890,2.2900,0.8294,1 +2.9221,-0.2305,0.8346,1 +1.4678,2.9256,0.3053,1 +0.7202,0.1857,0.3594,1 +-0.6650,-0.4448,0.4053,0 +0.5066,1.4030,0.8979,0 +-0.0438,1.4746,0.6404,0 +0.7781,-0.5580,0.6293,0 +2.6227,1.6948,0.8463,1 +1.8920,0.6328,0.3495,1 +1.2481,2.2437,0.5442,1 +1.9979,-0.0927,0.4671,0 +0.0617,1.4685,0.4226,0 +0.9411,-2.8816,0.5072,1 +1.1427,-0.5885,0.6889,0 +-1.7467,-1.7538,0.8860,1 +-2.5507,1.9841,0.5232,1 +0.0691,1.4204,0.1686,0 +1.2806,1.8900,0.2698,1 +-1.6073,0.3663,0.1724,0 +2.2003,-1.0221,0.2223,1 +1.2401,2.0628,0.0305,1 +0.7347,-1.1008,0.4318,0 +1.7125,-1.8606,0.6259,1 +2.8383,-0.3385,0.9131,1 +0.6376,-1.4281,0.5266,0 +-2.1714,1.2945,0.3611,1 +-1.5570,1.3089,0.7185,1 +-2.3617,-0.6180,0.4924,1 +-1.8794,-2.6679,0.5975,1 +-1.7007,-2.7917,0.7039,1 +2.7847,0.6791,0.3424,1 +-2.2916,1.1558,0.0952,1 +-0.0299,-0.7326,0.1686,0 +1.9209,-0.2245,0.5799,1 +1.2896,-1.0193,0.5936,0 +2.9664,-2.7227,0.7974,1 +-1.0826,-0.7011,0.5803,0 +-0.6004,2.2802,0.7586,1 +2.4821,-2.9089,0.1452,1 +-2.6573,-0.7231,0.1300,1 +2.0399,2.4365,0.0355,1 +2.0437,-2.7431,0.2736,1 +-2.4538,-2.8343,0.6375,1 +1.1206,2.0737,0.6630,1 +0.7864,2.8176,0.6416,1 +-2.6389,2.6110,0.5905,1 +0.6321,0.3615,0.5222,0 +-0.8806,-0.5241,0.1994,0 +-0.4553,0.9743,0.7135,0 +1.3267,1.5133,0.2516,1 +-2.0939,2.5119,0.8546,1 +-2.6831,-2.4527,0.8131,1 +-0.7785,2.9081,0.0401,1 +-0.3399,-2.2308,0.3952,1 +2.2939,-2.8523,0.5245,1 +1.8024,-2.4853,0.0342,1 +1.3956,-1.1208,0.1300,0 +1.8415,2.1352,0.3037,1 +-1.5277,0.3431,0.3301,0 +1.7017,2.7378,0.5841,1 +0.9154,-0.3083,0.9880,0 +2.0087,1.2077,0.5356,1 +1.9897,-1.2520,0.1570,1 +0.1265,-2.4157,0.3454,1 +-2.7386,1.8897,0.6511,1 +-1.2101,-0.8843,0.3253,0 +0.0063,0.1568,0.1488,0 +-1.0466,-1.0346,0.0688,0 +-0.1218,2.4773,0.9276,1 +1.8938,2.5527,0.9223,1 +-2.1925,0.1423,0.5756,1 +1.7037,1.2175,0.7466,1 +2.6539,0.8610,0.4026,1 +2.8785,0.1928,0.1678,1 +1.1235,0.3767,0.9068,0 +-0.5333,1.3678,0.0501,0 +0.2742,-1.4056,0.1069,0 +0.7928,0.1583,0.0785,0 +2.1038,0.8594,0.1734,1 +-2.8689,-0.7914,0.8476,1 +-1.2975,2.3477,0.5981,1 +2.3568,-0.4473,0.6756,1 +2.6684,1.7890,0.7258,1 +2.9890,-1.4606,0.2014,1 +1.6220,0.0857,0.4871,0 +2.2962,1.7774,0.5846,0 +2.1068,-0.2493,0.1898,1 +1.1480,-2.9670,0.1200,1 +2.3231,1.4812,0.9708,1 +0.4318,0.3083,0.5256,0 +1.9114,2.7202,0.4083,1 +-1.1534,-1.1885,0.5063,0 +0.3000,2.8595,0.1630,1 +2.9672,1.4168,0.5659,1 +-0.5872,2.6191,0.8953,1 +2.3925,2.5510,0.8463,1 +-0.2138,1.7754,0.3726,0 +-0.1115,-0.9808,0.4561,0 +-0.8730,-0.5088,0.0182,0 +-1.4386,2.1473,0.5896,1 +2.9864,-1.4525,0.5138,1 +1.1479,-0.3990,0.7770,0 +1.2928,-0.0517,0.9715,0 +-2.4517,-2.2232,0.9665,1 +-2.8432,-1.4807,0.4798,1 +-0.6052,1.3410,0.8344,0 +0.6714,2.9747,0.5496,1 +-0.9198,2.6766,0.9696,1 +0.3170,-0.4822,0.6716,0 +-1.4080,-1.3275,0.4797,1 +2.1471,1.7185,0.6768,1 +-0.6617,1.0122,0.2942,0 +2.4305,-2.3031,0.8539,1 +-0.6818,2.4323,0.2012,1 +-0.5004,2.3277,0.9921,1 +-0.0451,2.3700,0.5448,1 +1.5580,-0.9775,0.4860,1 +2.9338,0.9437,0.9258,1 +-1.3948,0.2432,0.4403,0 +2.0543,-1.6286,0.2746,1 +-0.5301,-2.2188,0.1953,1 +0.5910,2.7604,0.5328,1 +-2.1069,-0.5172,0.2798,1 +-1.3977,-1.7136,0.3677,1 +-0.9696,0.6344,0.1812,0 +1.1650,0.2086,0.0582,0 +1.1406,0.8704,0.8120,0 +-1.1078,-0.0376,0.3300,0 +-2.1593,-1.4612,0.0880,1 +1.2175,0.3784,0.6848,0 diff --git a/kimaya_solutions/test_playground/assets/ml_regression.csv b/kimaya_solutions/test_playground/assets/ml_regression.csv new file mode 100644 index 00000000..959d5a0d --- /dev/null +++ b/kimaya_solutions/test_playground/assets/ml_regression.csv @@ -0,0 +1,221 @@ +x1,x2,x3,y +6.88844,2.57954,3.36457,23.57172 +-1.90132,2.83799,2.42650,-5.72950 +-0.46806,0.83382,7.26490,1.54642 +5.11608,1.18369,2.00405,18.04119 +8.19493,4.82785,6.48174,29.48215 +4.59663,3.98838,5.47187,14.68572 +-0.55715,-3.99299,3.47337,2.23041 +9.33213,-0.22990,6.92248,35.64001 +-4.79015,3.05028,4.38959,-13.73673 +-2.02353,3.24845,5.34523,-6.42324 +-9.97714,-0.06422,6.94082,-29.22243 +7.40942,-3.08933,4.54009,35.04486 +-5.22768,4.67540,6.42544,-19.54274 +-3.59891,0.07941,7.46267,-6.45829 +-7.81884,0.51267,5.65249,-26.96827 +0.80567,4.63839,4.82549,0.03606 +1.75234,-0.55011,4.77029,8.64632 +-4.19341,-3.10609,1.49384,-8.02156 +2.25546,1.56659,3.81225,11.90895 +7.53541,4.23381,6.73968,28.48615 +7.96346,4.23082,4.32480,23.82994 +-4.48732,3.11629,6.79589,-12.03533 +7.90078,0.89801,7.59812,30.73352 +3.20491,4.96258,7.33553,10.07972 +5.86650,-4.17627,4.90226,26.65547 +6.90155,-2.56964,5.85191,32.16051 +-7.65731,-2.79539,6.35666,-20.18456 +-7.98785,-3.53642,5.58137,-16.05296 +-9.09532,0.73866,7.28013,-29.84804 +-9.46606,1.35000,4.85071,-31.51494 +1.51906,-1.08791,2.96112,9.53159 +-9.56727,4.61031,1.47978,-37.90050 +-7.52210,-2.89423,6.40597,-17.33333 +-1.48762,-3.98500,2.07936,1.07316 +-5.58341,1.46926,2.80235,-18.05956 +-9.21243,-3.99079,7.90588,-18.98594 +-6.01288,-1.41445,5.85279,-12.30581 +-6.61151,1.72641,7.73239,-22.83225 +-8.83898,1.76202,6.76340,-28.47287 +1.93583,-0.57686,1.39856,9.85744 +-0.56749,-0.90095,4.55290,1.01196 +-2.85697,3.37661,2.00746,-12.53867 +1.21200,-4.87564,5.93260,14.52444 +-4.38234,-2.59870,7.62503,-5.59499 +-2.95549,-2.12122,2.87361,-2.82145 +2.42154,2.15619,3.10414,7.44305 +-1.71164,1.50833,0.01219,-7.15108 +-5.21168,1.37399,3.02918,-15.77900 +7.50847,0.68151,3.31525,25.57106 +-1.63547,1.62196,0.37424,-5.57832 +-1.09296,-2.40773,1.26149,-2.20397 +1.22810,2.55485,7.07100,6.49083 +-0.10835,-1.87942,3.73514,6.34294 +6.24830,-3.11999,7.99536,28.20802 +2.66178,-4.16533,5.80443,20.97874 +3.57030,-1.83823,1.70820,15.90079 +4.34648,-4.97642,6.58185,25.55692 +-7.62192,1.49265,6.98923,-23.03727 +-4.40035,4.78515,0.80145,-19.28053 +-8.37309,-2.25286,3.62383,-25.30023 +5.84683,3.61360,1.06736,14.10526 +-3.05894,3.71864,2.22728,-13.76609 +-9.62851,-4.59337,5.44797,-28.34760 +8.76878,4.09851,0.33604,24.30622 +4.98270,2.01325,5.24289,18.20621 +2.80282,-1.27551,4.30343,10.58597 +-5.84312,0.87126,0.07118,-20.39010 +5.79246,2.18499,2.70605,21.28051 +2.41076,-4.58797,1.31088,16.63495 +-2.10416,0.48484,2.34726,-6.25608 +-0.43871,-2.60294,0.38605,2.93881 +-8.58274,-0.96831,2.62817,-24.57574 +-1.70557,-4.00600,7.26926,0.86968 +9.52459,-1.56348,3.83269,38.90191 +3.99191,-0.73465,2.41522,16.37972 +8.39378,1.26742,3.00457,26.03958 +9.49121,1.38879,0.52668,34.84347 +-8.77688,-4.92149,3.15046,-20.60396 +0.38007,-0.51456,3.90895,2.47756 +-1.53924,-1.31669,7.90767,0.98522 +-4.78167,2.77100,3.44977,-17.75914 +7.27158,2.02004,7.22409,29.36986 +-0.96776,1.76921,0.95128,-5.84151 +-9.15797,4.47961,1.72715,-35.23144 +-7.07291,-3.02030,3.02426,-19.80883 +9.77380,4.82989,1.18722,29.03294 +-1.88186,1.79929,7.02125,-7.58952 +-3.55079,-0.01559,3.98917,-9.08893 +3.40136,-2.98009,4.87816,19.73898 +9.25133,3.99008,6.54495,34.61647 +-9.29063,-3.51633,2.05506,-25.83464 +1.65896,2.18132,6.45644,4.59795 +-8.67282,-4.15357,6.95116,-18.42492 +-9.18736,-4.84715,6.75164,-20.58774 +-3.38811,-3.39310,1.19056,-9.76213 +0.09999,4.01090,4.01943,-5.61958 +1.47745,1.78571,6.44088,8.48181 +4.93931,4.05781,1.64884,7.63903 +0.70833,0.98614,6.60557,3.06325 +-2.22862,0.86388,6.81053,-2.99373 +5.96119,1.56985,0.00193,19.96776 +-4.91081,-4.34379,6.87907,-4.30785 +8.85894,-1.97195,3.26459,36.24845 +2.81970,-3.72679,2.29671,15.51176 +6.59881,-4.44473,0.28747,26.63544 +7.26650,2.17189,5.38835,28.28552 +-6.97252,4.86706,3.28912,-29.12267 +-9.05934,-0.29111,1.21094,-31.66707 +-9.35069,1.17400,5.03973,-28.11258 +-3.06664,-1.16586,6.21136,-2.81420 +-0.19361,3.81277,4.88096,-4.11743 +-3.24269,-3.75676,5.46024,-1.89398 +2.44075,2.88566,1.01687,8.94121 +8.33775,3.72535,5.44805,27.18346 +6.20502,0.19007,6.28391,27.81967 +-1.10841,2.56616,3.64376,-0.80463 +5.79117,-4.24660,0.35713,27.76480 +8.02143,4.44783,5.33209,26.07721 +1.43594,-2.84021,0.74781,10.80251 +5.58791,1.98502,3.36089,16.06496 +-3.89377,-3.86555,3.40776,-10.40702 +8.71510,-0.84359,0.79369,30.32555 +5.47637,2.34279,0.24561,13.67563 +-9.39732,4.19282,7.69794,-30.76288 +4.45086,-4.21461,0.56264,20.77609 +-3.04245,-4.90036,7.79459,1.84532 +6.38013,-4.29482,7.14748,33.55559 +3.47518,4.38262,0.98550,8.99943 +-9.85631,-1.30870,0.19720,-35.90024 +-6.26017,-3.87609,2.75560,-17.47895 +9.18343,-3.69842,7.73215,41.29768 +-4.14736,4.37127,7.66518,-11.90444 +2.71831,-3.15954,7.94361,21.76878 +-6.87194,3.97675,7.56543,-21.18690 +6.08781,-1.84109,1.94271,25.12142 +-1.60429,-4.53744,1.05787,-0.98190 +-9.58901,-4.22079,0.58569,-30.24703 +4.81758,-3.57717,3.37751,25.07183 +2.73932,-4.15444,3.55849,14.09705 +-8.84286,-0.91374,3.33780,-23.61165 +4.56361,-1.79329,1.63192,18.82356 +9.00537,2.96517,2.21576,31.90678 +1.16363,1.88200,6.36526,5.00334 +5.35281,-0.68284,1.98366,21.81068 +-0.93106,4.37105,1.14054,-10.36098 +-0.33424,-2.96360,0.01475,3.06435 +3.97983,1.18736,0.06221,11.52640 +2.57841,0.45208,1.24977,12.74569 +4.12588,-0.28565,5.42543,19.21585 +5.23990,-2.19912,7.87212,25.82473 +-7.58337,3.83718,0.32438,-30.98786 +1.63232,-1.03765,0.81625,10.05343 +-4.94784,-2.16603,6.04178,-7.62423 +-9.29098,2.92236,2.44483,-35.52852 +-3.20219,0.30185,1.99238,-8.92862 +-1.70339,-2.10308,4.15867,-0.68722 +1.47964,1.27140,4.25101,4.65004 +-1.93174,2.78550,6.30542,-3.55085 +-4.15492,-1.28196,5.03049,-7.27558 +-2.37144,0.91062,1.11626,-5.92108 +3.36517,-1.45942,3.78132,14.59446 +3.89391,-1.81760,5.21644,21.14031 +-8.79556,-1.99815,5.96168,-20.98050 +-9.48906,-0.28471,7.10836,-26.28234 +-9.79780,0.26828,0.53165,-32.14484 +4.83908,1.69008,0.05139,12.69230 +-9.17644,1.20877,7.99748,-25.00221 +4.54200,-2.73313,6.01291,21.76814 +-4.24152,-3.94540,3.68716,-7.74727 +-1.56580,3.97201,3.48216,-6.39786 +-1.05416,2.08828,4.19329,0.18195 +-1.11751,2.89338,3.11100,-1.70690 +6.13692,-1.10464,1.76128,25.78745 +1.73061,-4.50207,3.10678,18.42113 +-5.31941,-4.15343,1.49405,-9.76806 +-6.53252,1.10780,4.90005,-19.27379 +4.09847,0.12119,2.27539,17.35965 +-0.83411,1.31879,4.12899,-2.49810 +9.12937,4.54718,7.43808,34.86142 +-0.19596,2.04117,1.72336,-2.81823 +-4.68256,-4.56193,1.30286,-6.95688 +-7.19186,2.86679,5.44403,-24.18545 +9.41352,-1.03486,7.37114,38.34100 +-7.95322,3.82832,6.35832,-26.82118 +-3.54142,-0.44256,2.60115,-9.19041 +-2.62592,-2.90409,4.19612,-2.24038 +-6.24430,-2.98378,5.38134,-14.12576 +7.19989,-2.45361,2.75152,28.62179 +4.24961,-4.55497,7.47347,28.31599 +4.49210,-4.52531,6.47202,27.30644 +9.57787,-0.39488,0.94499,35.54740 +5.30883,-0.85987,7.35387,25.94256 +-1.18720,-4.22857,3.41548,3.76552 +-9.21297,-3.19611,3.92011,-29.03317 +-7.43829,3.71093,7.47569,-25.41142 +1.14108,-2.14494,4.32861,11.96619 +-5.97630,-2.03359,3.53427,-17.61133 +-4.78024,-2.68212,0.94984,-14.26780 +5.66987,-4.01099,5.86308,29.36082 +4.72167,1.59621,5.93537,20.99535 +0.30566,3.59096,0.97435,-3.07384 +4.74567,-1.41095,5.39906,21.82866 +4.06968,1.60608,1.77246,14.46324 +0.36307,1.74646,1.86883,-0.62066 +2.57023,-2.13169,1.37106,13.58144 +-3.44231,0.85431,0.20229,-15.27308 +-7.40354,-1.04419,7.80605,-19.21048 +5.30081,2.81444,6.19842,20.08179 +1.38996,1.95699,1.70766,3.48006 +5.19933,-1.46538,4.72822,20.07972 +2.57979,4.00810,0.86411,6.14148 +-2.82772,-0.44397,0.10108,-11.39649 +-5.59853,1.52763,5.28679,-22.14724 +-0.38170,-1.86056,6.78225,6.48742 +-4.81683,1.04306,5.62735,-12.08105 +-2.31815,-4.40820,0.30630,-5.73728 +4.52921,4.61691,2.74532,9.50800 +3.15662,-2.39893,5.37268,19.38693 +-3.90195,-1.43642,4.31611,-8.60725 +-9.56026,1.27830,0.19652,-35.97583 diff --git a/kimaya_solutions/test_playground/assets/sales.csv b/kimaya_solutions/test_playground/assets/sales.csv new file mode 100644 index 00000000..c73c27c3 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/sales.csv @@ -0,0 +1,181 @@ +date,region,product,units,unit_price,discount,revenue +2025-01-01,North,Notebook,16,20,0.1,288.00 +2025-01-01,South,Pen,44,120,0.05,5016.00 +2025-01-01,East,Notebook,79,45,0.15,3021.75 +2025-01-01,West,Bag,70,120,0.15,7140.00 +2025-01-02,North,Bottle,9,20,0.1,162.00 +2025-01-02,South,Bag,45,300,0.15,11475.00 +2025-01-02,East,Pen,76,45,0.05,3249.00 +2025-01-02,West,Pen,8,45,0.1,324.00 +2025-01-03,North,Pen,22,950,0.1,18810.00 +2025-01-03,South,Pen,62,300,0.1,16740.00 +2025-01-03,East,Bottle,51,300,0.05,14535.00 +2025-01-03,West,Bag,64,950,0.05,57760.00 +2025-01-04,North,Bag,40,300,0.1,10800.00 +2025-01-04,South,Bag,64,120,0.15,6528.00 +2025-01-04,East,Bag,33,120,0.05,3762.00 +2025-01-04,West,Bottle,66,120,0.1,7128.00 +2025-01-05,North,Bag,44,45,0.15,1683.00 +2025-01-05,South,Bottle,14,120,0,1680.00 +2025-01-05,East,Pen,18,20,0,360.00 +2025-01-05,West,Bottle,80,45,0,3600.00 +2025-01-06,North,Pen,39,45,0.05,1667.25 +2025-01-06,South,Notebook,59,20,0,1180.00 +2025-01-06,East,Bottle,51,45,0.05,2180.25 +2025-01-06,West,Notebook,15,20,0,300.00 +2025-01-07,North,Notebook,10,20,0.1,180.00 +2025-01-07,South,Bottle,21,45,0.05,897.75 +2025-01-07,East,Notebook,54,950,0,51300.00 +2025-01-07,West,Pen,24,20,0,480.00 +2025-01-08,North,Bottle,19,120,0.1,2052.00 +2025-01-08,South,Bag,8,120,0.15,816.00 +2025-01-08,East,Notebook,38,300,0.05,10830.00 +2025-01-08,West,Bag,33,20,0.1,594.00 +2025-01-09,North,Notebook,8,300,0.05,2280.00 +2025-01-09,South,Bag,67,950,0.1,57285.00 +2025-01-09,East,Pen,48,120,0.1,5184.00 +2025-01-09,West,Bag,7,950,0.05,6317.50 +2025-01-10,North,Notebook,37,20,0.05,703.00 +2025-01-10,South,Pen,26,20,0.15,442.00 +2025-01-10,East,Pen,70,20,0.05,1330.00 +2025-01-10,West,Pen,61,20,0.1,1098.00 +2025-01-11,North,Notebook,80,45,0.1,3240.00 +2025-01-11,South,Bottle,59,120,0,7080.00 +2025-01-11,East,Pen,9,300,0.15,2295.00 +2025-01-11,West,Pen,19,950,0,18050.00 +2025-01-12,North,Pen,18,20,0,360.00 +2025-01-12,South,Pen,34,20,0.05,646.00 +2025-01-12,East,Notebook,71,300,0.15,18105.00 +2025-01-12,West,Bottle,73,300,0.05,20805.00 +2025-01-13,North,Pen,60,300,0,18000.00 +2025-01-13,South,Notebook,58,950,0.05,52345.00 +2025-01-13,East,Notebook,66,120,0,7920.00 +2025-01-13,West,Notebook,51,120,0.1,5508.00 +2025-01-14,North,Bottle,7,300,0,2100.00 +2025-01-14,South,Notebook,44,45,0,1980.00 +2025-01-14,East,Bag,12,300,0.15,3060.00 +2025-01-14,West,Bag,31,950,0,29450.00 +2025-01-15,North,Notebook,41,20,0.1,738.00 +2025-01-15,South,Bottle,14,45,0.15,535.50 +2025-01-15,East,Pen,19,950,0.1,16245.00 +2025-01-15,West,Bag,64,45,0.1,2592.00 +2025-01-16,North,Bag,20,120,0,2400.00 +2025-01-16,South,Notebook,15,950,0.1,12825.00 +2025-01-16,East,Bag,32,20,0,640.00 +2025-01-16,West,Bag,10,300,0.1,2700.00 +2025-01-17,North,Bottle,63,45,0.1,2551.50 +2025-01-17,South,Bottle,66,950,0.15,53295.00 +2025-01-17,East,Bag,67,120,0.15,6834.00 +2025-01-17,West,Pen,25,300,0.1,6750.00 +2025-01-18,North,Bag,15,950,0,14250.00 +2025-01-18,South,Notebook,50,45,0.05,2137.50 +2025-01-18,East,Bag,13,20,0,260.00 +2025-01-18,West,Pen,42,300,0.05,11970.00 +2025-01-19,North,Bottle,61,45,0.1,2470.50 +2025-01-19,South,Notebook,24,950,0.15,19380.00 +2025-01-19,East,Notebook,47,950,0.05,42417.50 +2025-01-19,West,Bottle,26,45,0.15,994.50 +2025-01-20,North,Pen,56,120,0.05,6384.00 +2025-01-20,South,Bag,61,20,0.15,1037.00 +2025-01-20,East,Pen,55,950,0,52250.00 +2025-01-20,West,Bag,40,300,0.1,10800.00 +2025-01-21,North,Bag,65,120,0.1,7020.00 +2025-01-21,South,Notebook,33,950,0.05,29782.50 +2025-01-21,East,Bag,53,20,0.1,954.00 +2025-01-21,West,Bag,72,300,0.05,20520.00 +2025-01-22,North,Notebook,7,300,0.05,1995.00 +2025-01-22,South,Bag,32,20,0.15,544.00 +2025-01-22,East,Pen,40,950,0.05,36100.00 +2025-01-22,West,Bag,22,20,0.15,374.00 +2025-01-23,North,Bag,37,950,0.05,33392.50 +2025-01-23,South,Bag,31,20,0.1,558.00 +2025-01-23,East,Notebook,67,950,0,63650.00 +2025-01-23,West,Bag,47,300,0.1,12690.00 +2025-01-24,North,Bag,8,20,0.1,144.00 +2025-01-24,South,Pen,56,120,0.05,6384.00 +2025-01-24,East,Notebook,25,300,0.15,6375.00 +2025-01-24,West,Bag,42,45,0,1890.00 +2025-01-25,North,Bottle,76,300,0,22800.00 +2025-01-25,South,Bottle,9,950,0.15,7267.50 +2025-01-25,East,Bag,31,120,0.15,3162.00 +2025-01-25,West,Pen,66,950,0.1,56430.00 +2025-01-26,North,Notebook,38,120,0.1,4104.00 +2025-01-26,South,Bottle,44,300,0,13200.00 +2025-01-26,East,Pen,55,950,0.05,49637.50 +2025-01-26,West,Notebook,44,20,0.05,836.00 +2025-01-27,North,Bag,76,45,0.1,3078.00 +2025-01-27,South,Notebook,19,20,0.15,323.00 +2025-01-27,East,Bottle,32,120,0.1,3456.00 +2025-01-27,West,Notebook,47,300,0.1,12690.00 +2025-01-28,North,Pen,68,300,0.1,18360.00 +2025-01-28,South,Bag,22,300,0.05,6270.00 +2025-01-28,East,Bottle,46,45,0,2070.00 +2025-01-28,West,Pen,65,45,0.1,2632.50 +2025-01-29,North,Pen,50,45,0.05,2137.50 +2025-01-29,South,Pen,39,950,0.15,31492.50 +2025-01-29,East,Bag,48,120,0.1,5184.00 +2025-01-29,West,Bag,42,950,0,39900.00 +2025-01-30,North,Bottle,44,300,0.15,11220.00 +2025-01-30,South,Pen,38,120,0.15,3876.00 +2025-01-30,East,Bag,16,45,0.1,648.00 +2025-01-30,West,Bag,21,20,0,420.00 +2025-01-31,North,Bottle,26,120,0,3120.00 +2025-01-31,South,Bag,6,950,0.1,5130.00 +2025-01-31,East,Pen,54,950,0.1,46170.00 +2025-01-31,West,Bag,24,120,0.1,2592.00 +2025-02-01,North,Pen,68,20,0.05,1292.00 +2025-02-01,South,Pen,47,120,0.05,5358.00 +2025-02-01,East,Bag,51,120,0,6120.00 +2025-02-01,West,Bottle,29,45,0.05,1239.75 +2025-02-02,North,Notebook,48,120,0,5760.00 +2025-02-02,South,Pen,27,20,0.15,459.00 +2025-02-02,East,Bag,39,45,0.1,1579.50 +2025-02-02,West,Notebook,48,950,0.15,38760.00 +2025-02-03,North,Pen,11,300,0.15,2805.00 +2025-02-03,South,Bag,45,950,0,42750.00 +2025-02-03,East,Bag,56,300,0.05,15960.00 +2025-02-03,West,Bag,54,950,0.15,43605.00 +2025-02-04,North,Notebook,18,300,0.05,5130.00 +2025-02-04,South,Notebook,69,45,0,3105.00 +2025-02-04,East,Bag,44,300,0,13200.00 +2025-02-04,West,Bottle,18,120,0.05,2052.00 +2025-02-05,North,Pen,8,45,0.15,306.00 +2025-02-05,South,Notebook,48,300,0,14400.00 +2025-02-05,East,Bag,35,20,0.15,595.00 +2025-02-05,West,Pen,76,20,0.05,1444.00 +2025-02-06,North,Notebook,11,45,0,495.00 +2025-02-06,South,Bottle,72,45,0.05,3078.00 +2025-02-06,East,Bottle,67,20,0.05,1273.00 +2025-02-06,West,Notebook,36,20,0.15,612.00 +2025-02-07,North,Pen,11,950,0.05,9927.50 +2025-02-07,South,Bag,48,950,0.15,38760.00 +2025-02-07,East,Pen,70,20,0.05,1330.00 +2025-02-07,West,Pen,27,300,0.05,7695.00 +2025-02-08,North,Bottle,48,300,0.05,13680.00 +2025-02-08,South,Bag,21,300,0.1,5670.00 +2025-02-08,East,Bottle,17,950,0,16150.00 +2025-02-08,West,Bag,39,120,0.15,3978.00 +2025-02-09,North,Bottle,34,300,0.05,9690.00 +2025-02-09,South,Notebook,8,950,0.05,7220.00 +2025-02-09,East,Pen,29,300,0,8700.00 +2025-02-09,West,Pen,8,120,0.15,816.00 +2025-02-10,North,Notebook,33,45,0.1,1336.50 +2025-02-10,South,Notebook,30,20,0.05,570.00 +2025-02-10,East,Pen,16,300,0.1,4320.00 +2025-02-10,West,Pen,25,120,0.1,2700.00 +2025-02-11,North,Notebook,57,300,0,17100.00 +2025-02-11,South,Bag,43,20,0.1,774.00 +2025-02-11,East,Notebook,32,300,0.1,8640.00 +2025-02-11,West,Bottle,73,300,0.05,20805.00 +2025-02-12,North,Bag,21,45,0.15,803.25 +2025-02-12,South,Bag,49,300,0.15,12495.00 +2025-02-12,East,Bottle,29,950,0.15,23417.50 +2025-02-12,West,Bag,29,300,0.1,7830.00 +2025-02-13,North,Bottle,14,45,0.1,567.00 +2025-02-13,South,Bag,33,950,0.05,29782.50 +2025-02-13,East,Bottle,31,950,0.1,26505.00 +2025-02-13,West,Notebook,6,20,0.05,114.00 +2025-02-14,North,Bottle,12,120,0.1,1296.00 +2025-02-14,South,Bottle,61,20,0.15,1037.00 +2025-02-14,East,Bag,7,120,0.05,798.00 +2025-02-14,West,Pen,24,45,0.15,918.00 diff --git a/kimaya_solutions/test_playground/assets/students.csv b/kimaya_solutions/test_playground/assets/students.csv new file mode 100644 index 00000000..5ead6578 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/students.csv @@ -0,0 +1,13 @@ +student_id,name,age,grade,score,attendance,department +S001,Alicia,21,A,88.5,94.0,CSE +S002,Ben,19,B,72.0,81.0,ECE +S003,Carmen,22,A,91.2,96.0,CSE +S004,Dev,20,C,60.5,70.0,ME +S005,Eli,23,B,75.3,84.0,ECE +S006,Farah,21,A,84.7,90.0,ECE +S007,Gio,20,B,78.8,86.0,CSE +S008,Hana,22,A,89.1,93.0,ME +S009,Ishan,19,C,66.4,74.0,CSE +S010,Jia,21,B,79.6,88.0,ECE +S011,Karan,20,B,73.9,77.0,ME +S012,Lina,22,A,92.4,98.0,CSE diff --git a/kimaya_solutions/test_playground/assets/students_demo.csv b/kimaya_solutions/test_playground/assets/students_demo.csv new file mode 100644 index 00000000..d01db9e1 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/students_demo.csv @@ -0,0 +1,3 @@ +name,age,grade +A,20,A +B,21,B diff --git a/kimaya_solutions/test_playground/assets/weather_timeseries.csv b/kimaya_solutions/test_playground/assets/weather_timeseries.csv new file mode 100644 index 00000000..b63d15b8 --- /dev/null +++ b/kimaya_solutions/test_playground/assets/weather_timeseries.csv @@ -0,0 +1,61 @@ +date,temp_c,humidity,rain_mm +2025-01-01,21.90,79,7.06 +2025-01-02,24.19,82,7.38 +2025-01-03,21.32,45,5.34 +2025-01-04,25.61,57,0.67 +2025-01-05,29.57,75,0.00 +2025-01-06,25.18,54,1.54 +2025-01-07,24.26,54,4.97 +2025-01-08,28.73,87,0.00 +2025-01-09,29.42,55,2.71 +2025-01-10,26.01,46,0.00 +2025-01-11,26.59,62,0.00 +2025-01-12,27.43,90,3.31 +2025-01-13,27.10,72,0.00 +2025-01-14,24.76,53,5.80 +2025-01-15,28.63,51,5.92 +2025-01-16,24.06,88,3.28 +2025-01-17,25.89,85,4.43 +2025-01-18,29.47,81,0.02 +2025-01-19,26.01,82,0.68 +2025-01-20,26.29,46,3.70 +2025-01-21,26.85,83,1.65 +2025-01-22,27.29,79,0.92 +2025-01-23,28.04,81,5.98 +2025-01-24,26.26,81,5.16 +2025-01-25,23.74,52,7.92 +2025-01-26,29.92,50,4.78 +2025-01-27,25.15,49,1.05 +2025-01-28,25.15,94,3.41 +2025-01-29,26.52,52,6.48 +2025-01-30,23.96,90,3.64 +2025-01-31,24.69,80,8.68 +2025-02-01,24.44,47,0.00 +2025-02-02,23.28,49,5.39 +2025-02-03,28.79,71,4.83 +2025-02-04,23.93,61,2.99 +2025-02-05,28.94,65,3.23 +2025-02-06,25.28,53,4.83 +2025-02-07,26.48,78,0.73 +2025-02-08,26.29,83,1.91 +2025-02-09,31.38,77,1.23 +2025-02-10,22.17,85,2.09 +2025-02-11,22.81,61,0.33 +2025-02-12,24.97,80,0.00 +2025-02-13,29.10,65,6.98 +2025-02-14,21.76,84,1.14 +2025-02-15,27.07,66,1.65 +2025-02-16,26.13,88,6.07 +2025-02-17,25.03,76,0.46 +2025-02-18,23.38,48,3.10 +2025-02-19,26.55,85,2.33 +2025-02-20,23.65,82,0.99 +2025-02-21,21.88,93,1.38 +2025-02-22,23.75,83,2.03 +2025-02-23,22.04,46,7.76 +2025-02-24,29.37,88,2.26 +2025-02-25,23.78,62,0.00 +2025-02-26,24.31,56,0.60 +2025-02-27,23.58,83,0.00 +2025-02-28,25.78,66,1.53 +2025-03-01,30.08,55,0.59 diff --git a/kimaya_solutions/test_playground/basics/boss.py b/kimaya_solutions/test_playground/basics/boss.py new file mode 100644 index 00000000..0c06ee96 --- /dev/null +++ b/kimaya_solutions/test_playground/basics/boss.py @@ -0,0 +1,54 @@ +choice = 'y' + +while choice =='y'or choice =='Y' : # make 'Y' valid too + try: + # typecast the below 2 to a list + + numbers =list(input("Enter the input numbers separated by spaces: ")) + operators = input("Enter operators between them: ") + + # check length matching + + if len(numbers) != len(operators): # this seems odd... u might say it's ... off by one + print("What u doin fam ? ") # replace wiht better message :) + continue + + flag = False # huh this seems inverted + for i in range(len(numbers)): # indexing range fix + a, b, op = numbers[i-1], numbers[i], operators[i] + # correct the ops + match op: + case '+': + c = a + b + case '-': + c = a * b + case '*': + c = a / b + case '/': + c = a % b + case '%': + c = a - b + case '//': + c = a ** b + case '**': + c = a // b + case _: + flag = True + if not flag: + print("Invalid ops vro") + break + + numbers[i-1] = c + if not flag: + continue + print(f"Output: numbers[-1]") + + except Exception as e: + print(f"Exception: {e}") # print exception + + finally: + choice = input("Do you want to continue? [y/n] : ") + +# can you make the code shorter and with improved answer? +# like handling any basic arithmetic equation (that may have brackets too) ? +# u might wanna find a special function in python \ No newline at end of file diff --git a/kimaya_solutions/test_playground/basics/conditionals.py b/kimaya_solutions/test_playground/basics/conditionals.py new file mode 100644 index 00000000..1e152709 --- /dev/null +++ b/kimaya_solutions/test_playground/basics/conditionals.py @@ -0,0 +1,61 @@ +# correct if else ladder to check if person is underage, normal citizen or senior citizen +# [0,18) -> underage, [18,60) normal age, [60,inf) senior citizen +# bonus, can you reduce ladder to a one liner? +age = int(input("Enter age")) # ahh yes age is str , definitely + +if age < 18: + print("Underage") +elif age >=18 or age < 60: + print("Normal citizen") +else: + print("Senior citizen") + +print("Underage") if age < 18 else print("Normal citizen") if age >=18 or age < 60 else print("Senior citizen") + + +# complete the match + +day = int(input("Enter the day number")) # dont forget to typecast to int + +print("Today is: ", end="") # how can you avoid printing newline here? + +match day: + case 1: + print("Monday") + case 2: + print("Tuesday") + case 3: + print("Wednesday") + case 4: + print("Thursday") + case 5: + print("Friday") + case 6: + print("Satday") + case 7: + print("Sunday") + + +# implement try catch + +try: + print(1/0) +except ZeroDivisionError: # ahh fix the syntax, also when u don't know the error what will u use? + print("what u tryna do bro") +finally: + print("So u done?") + + +try: + x=float(input("Enter a no : ")) + print(1/x) +except Exception: + print("what u tryna do bro") +finally: + print("So u done?") + + + + + + diff --git a/kimaya_solutions/test_playground/basics/hello.py b/kimaya_solutions/test_playground/basics/hello.py new file mode 100644 index 00000000..d26f224b --- /dev/null +++ b/kimaya_solutions/test_playground/basics/hello.py @@ -0,0 +1,2 @@ +# yayy +print("Hello World") \ No newline at end of file diff --git a/kimaya_solutions/test_playground/basics/input_output.py b/kimaya_solutions/test_playground/basics/input_output.py new file mode 100644 index 00000000..88a14a5f --- /dev/null +++ b/kimaya_solutions/test_playground/basics/input_output.py @@ -0,0 +1,32 @@ +# typecast all inputs as prompted + +# note: all inputs are strs by default + + +integer = int(input("Enter an integer: ")) # change only this line + +print(type(integer)) # should output 'int' + +number = float(input("Enter a number (floating point allowed): ")) # change only this line + +print(type(number)) # should output 'float' + +array = list(input("Enter an array of numbers: ")) # change only this line + +print(type(array)) # should output 'list' + +nums = "1,2,3,4" + +print(nums) # print it as a string joined by commas : 1,2,3,4 + + +name = input("Enter your name: ") + +print(f"Hello, {name}") # complete f string + +x,y,z = 67, 420 , 9000 + + +# 6 print statements is too much, can you get the same output in one print statement ? +print(x,y,z, sep="\n") + diff --git a/kimaya_solutions/test_playground/basics/loops.py b/kimaya_solutions/test_playground/basics/loops.py new file mode 100644 index 00000000..5f734d9c --- /dev/null +++ b/kimaya_solutions/test_playground/basics/loops.py @@ -0,0 +1,21 @@ +# print all multiples of 5 in [1,100] + +for i in range(5,101,5): # start, stop, step , range is [start,stop) + print(i,end=" ") + + +names = ["Avanish","Awwab","Nathan"] +nicknames = ["Amar","Akbar","Anthony"] +hobbies = ["Marvel","Anime","Games"] + +for name,nickname,hobby in zip(names, nicknames, hobbies): # wow cool new function + print("\nName:",name , "Nickname:",nickname, "Hobbies: ", hobbies) # fill this at least + +# try zip for adding this array to the above 2 and printing all 3 in loop + + +choice = 'y' + +while choice.lower() == 'y': # can you make this case insensitive with one more condition? + choice = input("Enter choice [y/n] : ") + diff --git a/kimaya_solutions/test_playground/basics/vars_and_ops.py b/kimaya_solutions/test_playground/basics/vars_and_ops.py new file mode 100644 index 00000000..5b90a2ed --- /dev/null +++ b/kimaya_solutions/test_playground/basics/vars_and_ops.py @@ -0,0 +1,25 @@ +# declare some variables + +x = 10 +y = 5 + +print(x+y) # come on think, this ain't javascript + +num1 , num2 = 6 , 7 + +print(num1 // num2) # huh this shouldnt output 0, as a bonus can u also round to 2 decimal places? +print(round(num1/num2,2)) + +a , n = 1, 31 + +a = 2**31 # can you replace this loop with a one liner? +print(a) + +# match the correct statements wrt bitwise operators + +print("AND operator:", " & ") +print("OR operator:", " | ") +print("XOR operator:", " ^ ") + + + diff --git a/kimaya_solutions/test_playground/intermediate/boss.py b/kimaya_solutions/test_playground/intermediate/boss.py new file mode 100644 index 00000000..a0c9ef51 --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/boss.py @@ -0,0 +1,275 @@ +"""Practice shopping cart flow with Tkinter UI.""" + +from pathlib import Path +import csv +import json +from typing import Any, Dict, List + +try: + import tkinter as tk + from tkinter import ttk, messagebox +except ImportError: # pragma: no cover + tk = None + ttk = None + messagebox = None + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +ASSETS.mkdir(parents=True, exist_ok=True) +BILLS_CSV = ASSETS / "bills.csv" + +PRODUCTS = { + 1: {"name": "Notebook", "price": 45.0}, + 2: {"name": "Pen Pack", "price": 20.0}, + 3: {"name": "Backpack", "price": 950.0}, + 4: {"name": "Bottle", "price": 300.0}, +} + + +# helper function for practice (UI does not depend on this) +def compute_tax(total: float, rate: float = 0.18) -> float: + """Return tax amount.""" + return total * rate # hint: should use rate, not fixed 0.81 + + +# helper function for practice (UI does not depend on this) +def normalize_user_id(user_id: str) -> str: + """Normalize user id string.""" + return user_id.lower().strip() # hint: app expects lowercase id in filenames + + +class CartManager: + # manage per-user cart in JSON file + def __init__(self, user_id: str): + self.user_id = user_id + self.path = ASSETS / f"cart_{user_id}.json" + self.cart: Dict[str, Any] = {"items": []} + self.load() + + def load(self) -> None: + """Load cart from disk if present.""" + if self.path.exists(): + self.cart = json.loads(self.path.read_text(encoding="utf-8")) + else: + self.cart = {"items": []} + + def save(self) -> None: + """Persist cart to disk.""" + self.path.write_text(json.dumps(self.cart, indent=2), encoding="utf-8") + + def add_item(self, item_id: int, qty: int = 1) -> None: + """Add product and quantity to cart.""" + if item_id not in PRODUCTS: + raise ValueError("invalid item id") + if qty <= 0: + raise ValueError("qty must be positive") + + for row in self.cart["items"]: + if row["item_id"] == item_id: + row["qty"] += qty + self.save() + return + + self.cart["items"].append({"item_id": item_id, "qty": qty}) + self.save() + + def remove_item(self, item_id: int) -> bool: + """Remove one product row from cart.""" + before = len(self.cart["items"]) + self.cart["items"] = [row for row in self.cart["items"] if row["item_id"] != item_id] + changed = len(self.cart["items"]) != before + if changed: + self.save() + return changed + + def clear(self) -> None: + """Clear cart and delete file.""" + self.cart = {"items": []} + if self.path.exists(): + self.path.unlink() + + def list_items(self) -> List[Dict[str, Any]]: + """Return expanded cart rows for display.""" + out: List[Dict[str, Any]] = [] + for row in self.cart["items"]: + item = PRODUCTS.get(row["item_id"], {"name": "Unknown", "price": 0.0}) + out.append( + { + "item_id": row["item_id"], + "name": item["name"], + "price": item["price"], + "qty": row["qty"], + "line_total": item["price"] * row["qty"], + } + ) + return out + + def total(self) -> float: + """Return cart grand total.""" + return sum(row["line_total"] for row in self.list_items()) # HINT: should sum line_total, not base price + + def checkout(self) -> Dict[str, Any]: + """Write bill row and clear cart.""" + items = self.list_items() + total = self.total() + summary = {"user": self.user_id, "items": items, "total": round(total, 2)} + + exists = BILLS_CSV.exists() + with BILLS_CSV.open("a", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + if not exists: + writer.writerow(["user", "items", "total"]) + writer.writerow([self.user_id, json.dumps(items), f"{total:.2f}"]) + + self.clear() + return summary + + +class ShoppingApp(tk.Tk): + # Tkinter app kept clean and fully working + def __init__(self): + super().__init__() + self.title("Workshop Shopping App") + self.geometry("760x520") + self.resizable(False, False) + + self.user_var = tk.StringVar(value="student1") + self.item_var = tk.StringVar(value="1") + self.qty_var = tk.StringVar(value="1") + + self.cart_manager = CartManager(self.user_var.get()) + + self._build_layout() + self.refresh_cart_view() + + def _build_layout(self) -> None: + # top controls + top = ttk.Frame(self, padding=12) + top.pack(fill="x") + + ttk.Label(top, text="User ID:").grid(row=0, column=0, sticky="w", padx=4, pady=4) + ttk.Entry(top, textvariable=self.user_var, width=18).grid(row=0, column=1, sticky="w", padx=4, pady=4) + ttk.Button(top, text="Switch User", command=self.switch_user).grid(row=0, column=2, padx=4, pady=4) + + ttk.Label(top, text="Item:").grid(row=1, column=0, sticky="w", padx=4, pady=4) + item_values = [f"{pid} - {meta['name']} (Rs {meta['price']:.2f})" for pid, meta in PRODUCTS.items()] + self.item_combo = ttk.Combobox(top, values=item_values, state="readonly", width=35) + self.item_combo.grid(row=1, column=1, columnspan=2, sticky="w", padx=4, pady=4) + self.item_combo.current(0) + + ttk.Label(top, text="Qty:").grid(row=1, column=3, sticky="e", padx=4, pady=4) + ttk.Entry(top, textvariable=self.qty_var, width=8).grid(row=1, column=4, sticky="w", padx=4, pady=4) + + ttk.Button(top, text="Add To Cart", command=self.add_selected_item).grid(row=1, column=5, padx=6, pady=4) + + # tree for cart rows + middle = ttk.Frame(self, padding=(12, 0, 12, 0)) + middle.pack(fill="both", expand=True) + + cols = ("item_id", "name", "price", "qty", "line_total") + self.tree = ttk.Treeview(middle, columns=cols, show="headings", height=14) + for c in cols: + self.tree.heading(c, text=c) + self.tree.column(c, width=120, anchor="center") + self.tree.pack(side="left", fill="both", expand=True) + + scroll = ttk.Scrollbar(middle, orient="vertical", command=self.tree.yview) + scroll.pack(side="right", fill="y") + self.tree.configure(yscrollcommand=scroll.set) + + # bottom actions + bottom = ttk.Frame(self, padding=12) + bottom.pack(fill="x") + + self.total_label = ttk.Label(bottom, text="Total: Rs 0.00") + self.total_label.pack(side="left") + + ttk.Button(bottom, text="Remove Selected", command=self.remove_selected).pack(side="right", padx=4) + ttk.Button(bottom, text="Checkout", command=self.checkout).pack(side="right", padx=4) + ttk.Button(bottom, text="Clear Cart", command=self.clear_cart).pack(side="right", padx=4) + + def _selected_item_id(self) -> int: + # parse id from combobox text like "1 - Notebook ..." + text = self.item_combo.get().strip() + return int(text.split(" - ")[0]) + + def switch_user(self) -> None: + # switch active cart file + user_id = self.user_var.get().strip() + if not user_id: + messagebox.showerror("Invalid user", "User ID cannot be empty") + return + self.cart_manager = CartManager(user_id) + self.refresh_cart_view() + + def add_selected_item(self) -> None: + # add chosen product with quantity + try: + item_id = self._selected_item_id() + qty = int(self.qty_var.get()) + self.cart_manager.add_item(item_id, qty) + self.refresh_cart_view() + self.qty_var.set("1") + except ValueError as exc: + messagebox.showerror("Input error", str(exc)) + + def refresh_cart_view(self) -> None: + # redraw tree rows and total + for iid in self.tree.get_children(): + self.tree.delete(iid) + + for row in self.cart_manager.list_items(): + self.tree.insert( + "", + "end", + values=( + row["item_id"], + row["name"], + f"{row['price']:.2f}", + row["qty"], + f"{row['line_total']:.2f}", + ), + ) + + self.total_label.config(text=f"Total: Rs {self.cart_manager.total():.2f}") + + def remove_selected(self) -> None: + # remove selected product row + selected = self.tree.selection() + if not selected: + messagebox.showinfo("Select row", "Choose a row to remove") + return + + values = self.tree.item(selected[0], "values") + item_id = int(values[0]) + self.cart_manager.remove_item(item_id) + self.refresh_cart_view() + + def clear_cart(self) -> None: + # clear current user cart + self.cart_manager.clear() + self.refresh_cart_view() + + def checkout(self) -> None: + # complete checkout and show summary + if not self.cart_manager.list_items(): + messagebox.showinfo("Empty cart", "Cart is empty") + return + + summary = self.cart_manager.checkout() + self.refresh_cart_view() + messagebox.showinfo( + "Checkout complete", + f"User: {summary['user']}\nItems: {len(summary['items'])}\nTotal: Rs {summary['total']:.2f}", + ) + + +def run_tk_app() -> None: + """Start Tkinter shopping app.""" + if tk is None: + raise ImportError("Tkinter is not available in this Python environment") + app = ShoppingApp() + app.mainloop() + + +if __name__ == "__main__": + run_tk_app() diff --git a/kimaya_solutions/test_playground/intermediate/class_basics.py b/kimaya_solutions/test_playground/intermediate/class_basics.py new file mode 100644 index 00000000..24c06d75 --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/class_basics.py @@ -0,0 +1,65 @@ +"""Practice simple classes and methods.""" + + +class Rectangle: + # store width and height + def __init__(self, width: float, height: float): + self.width = width + self.height = height + + def area(self) -> float: + """Return rectangle area.""" + return self.width * self.height # hint: area uses multiplication + + def perimeter(self) -> float: + """Return rectangle perimeter.""" + return 2 * self.width + 2 * self.height # hint: both sides should be doubled + + +class BankAccount: + # keep owner identity and current balance + def __init__(self, owner: str, balance: float = 0.0): + self.owner = owner + self.balance = balance + + def deposit(self, amount: float) -> float: + """Deposit and return updated balance.""" + if amount <= 0: # hint: zero deposit should usually be rejected too + raise ValueError("amount must be positive") + self.balance += amount + return self.balance + + def withdraw(self, amount: float) -> float: + """Withdraw and return updated balance.""" + if amount <= 0: + raise ValueError("amount must be positive") + if amount > self.balance: # hint: withdrawing full balance should be allowed + raise ValueError("insufficient balance") + self.balance -= amount # hint: withdraw should subtract + return self.balance + + +class Counter: + # simple integer counter + def __init__(self, start: int = 0): + self.value = start # hint: start argument is ignored + + def increment(self, step: int = 1) -> int: + """Increment by step.""" + self.value += step # hint: increment should add + return self.value + + def reset(self, to: int = 0) -> None: + """Reset counter value.""" + self.value = to # hint: extra +1 should not be here + + +if __name__ == "__main__": + r = Rectangle(5, 3) + print("Rectangle:", r.area(), r.perimeter()) + acc = BankAccount("Ada", 100.0) + print("Balance:", acc.deposit(50), acc.withdraw(20)) + c = Counter(10) + c.increment() + c.reset() + print("Counter:", c.value) diff --git a/kimaya_solutions/test_playground/intermediate/csv_handler.py b/kimaya_solutions/test_playground/intermediate/csv_handler.py new file mode 100644 index 00000000..b6d0452f --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/csv_handler.py @@ -0,0 +1,68 @@ +"""Practice CSV file CRUD helpers.""" + +from pathlib import Path +import csv +from typing import Any, Dict, List + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +ASSETS.mkdir(parents=True, exist_ok=True) + + +def csv_create(filename: str, headers: List[str], rows: List[List[Any]]) -> Path: + # create csv with header + rows + p = ASSETS / filename + with p.open("w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(headers) # hint: last header is accidentally dropped + writer.writerows(rows) + return p + + +def csv_read(filename: str) -> List[Dict[str, str]]: + # read csv rows as dictionaries + p = ASSETS / filename + with p.open("r", newline="", encoding="utf-8") as f: + reader = csv.DictReader(f) + return list(reader) # hint: returns only first row + + +def csv_append(filename: str, row: List[Any]) -> Path: + # append one data row + p = ASSETS / filename + with p.open("a", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(row) # hint: last value in appended row is dropped + return p + + +def csv_update_row_by_index(filename: str, index: int, new_row: List[Any]) -> bool: + # update row by index, index 0 reserved for header + p = ASSETS / filename + with p.open("r", newline="", encoding="utf-8") as f: + rows = list(csv.reader(f)) + + if index < 1 or index >= len(rows): + return False + + rows[index] = new_row # hint: this shifts index by one extra position + + with p.open("w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerows(rows) + return True + + +def csv_delete(filename: str) -> bool: + # delete csv file if it exists + p = ASSETS / filename + if p.exists(): + p.unlink() + return True # hint: incorrectly returns False even on success + return False # hint: should return False when file is missing + + +if __name__ == "__main__": + headers = ["name", "age", "grade"] + rows = [["A", 20, "A"], ["B", 21, "B"]] + csv_create("students_demo.csv", headers, rows) + print(csv_read("students_demo.csv")) diff --git a/kimaya_solutions/test_playground/intermediate/dict_ops.py b/kimaya_solutions/test_playground/intermediate/dict_ops.py new file mode 100644 index 00000000..668a208a --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/dict_ops.py @@ -0,0 +1,35 @@ +"""Practice common dictionary utilities.""" + +from typing import Any, Dict, Iterable + + +# swap keys and values +def invert_dict(d: Dict[Any, Any]) -> Dict[Any, Any]: + """Return value->key mapping.""" + return {v: k for k, v in d.items() if k} # hint: this wrongly skips falsy keys like 0 or "" + + +# merge all dicts from left to right (latest key wins) +def merge_dicts(dicts: Iterable[Dict[Any, Any]]) -> Dict[Any, Any]: + """Return a merged dict.""" + merged: Dict[Any, Any] = {} + for chunk in dicts: + for k, v in chunk.items(): + if k not in merged: + merged[k] = v # hint: this keeps first value, not latest override + return merged + + +# count keys that begin with a given prefix +def count_keys_with_prefix(d: Dict[str, Any], prefix: str) -> int: + """Return number of keys that match prefix.""" + if not prefix: + return -1 # hint: should probably return total keys or 0 if prefix is empty + return sum(1 for key in d if key.endswith(prefix)) # hint: startswith is expected + + +if __name__ == "__main__": + sample = {"pre_name": "A", "pre_age": 20, "city": "BLR"} + print(invert_dict({"a": 1, "b": 2, 0: 7})) + print(merge_dicts([{"x": 1}, {"y": 2}, {"x": 9}])) + print(count_keys_with_prefix(sample, "pre_")) diff --git a/kimaya_solutions/test_playground/intermediate/inheritance.py b/kimaya_solutions/test_playground/intermediate/inheritance.py new file mode 100644 index 00000000..9a0e4fdc --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/inheritance.py @@ -0,0 +1,48 @@ +"""Practice inheritance and method overriding.""" + +from typing import List + + +class Person: + # base class with shared identity fields + def __init__(self, name: str, age: int): + self.name = name + self.age = age + + def greet(self) -> str: + """Return a basic greeting.""" + return f"Hi, I am {self.age}." # hint: age used instead of name + + +class Employee(Person): + # subclass adds employee id + def __init__(self, name: str, age: int, employee_id: str): + super().__init__(name, age) + self.employee_id = employee_id + + def greet(self) -> str: + """Return employee greeting.""" + return f"Hi, I am {self.name} and my id is {self.employee_id}".lower() # hint: lower() changes intended casing + + +class Manager(Employee): + # manager tracks a team list + def __init__(self, name: str, age: int, employee_id: str, team: List[Employee] = None): + super().__init__(name, age, employee_id) + self.team = team or [] + + def add_member(self, employee: Employee): + """Add one employee to team.""" + self.team.append(employee.name) # hint: store Employee object for richer usage + + def team_size(self) -> int: + """Return count of team members.""" + return len(self.team) - 1 # hint: unnecessary -1 causes off-by-one + + +if __name__ == "__main__": + e1 = Employee("Ada", 30, "E100") + mgr = Manager("Grace", 40, "M001") + mgr.add_member(e1) + print(e1.greet()) + print(mgr.greet(), "Team size:", mgr.team_size()) diff --git a/kimaya_solutions/test_playground/intermediate/json_handler.py b/kimaya_solutions/test_playground/intermediate/json_handler.py new file mode 100644 index 00000000..66e4850c --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/json_handler.py @@ -0,0 +1,61 @@ +"""Practice JSON file CRUD helpers.""" + +from pathlib import Path +import json +from typing import Any + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +ASSETS.mkdir(parents=True, exist_ok=True) + + +def json_read(filename: str) -> Any: + # load json data from file + p = ASSETS / filename + if not p.exists(): + raise FileNotFoundError(f"{filename} not found") # hint: expected behavior may be FileNotFoundError + return json.loads(p.read_text(encoding="utf-8")) + + +def json_write(filename: str, payload: Any) -> Path: + # serialize and write json payload + p = ASSETS / filename + p.write_text(json.dumps(payload, indent=4), encoding="utf-8") # hint: pretty formatting (indent) intentionally removed + return p + + +def json_update_key(filename: str, key_path: str, value: Any) -> bool: + # create/update value at dotted key path + """Update nested key path.""" + data = json_read(filename) + if not key_path: + return False + + keys = key_path.split(".") + cur = data + for k in keys[:-1]: + if k not in cur or not isinstance(cur[k], dict): + cur[k] = {} + cur = cur[k] + cur[keys[-1]] = value # hint: empty key_path breaks here + json_write(filename, data) + return True # hint: incorrectly returns False on success + + +def json_delete_key(filename: str, key_path: str) -> bool: + # delete key at dotted path if present + data = json_read(filename) + keys = key_path.split(".") if key_path else [] + cur = data + for k in keys[:-1]: + cur = cur.get(k, {}) + if keys and keys[-1] in cur: + del cur[keys[-1]] + json_write(filename, data) + return True + return False # hint: should return False when key not found + + +if __name__ == "__main__": + sample = {"a": {"b": 1}, "list": [1, 2, 3]} + json_write("demo.json", sample) + print(json_read("demo.json")) diff --git a/kimaya_solutions/test_playground/intermediate/lambdas.py b/kimaya_solutions/test_playground/intermediate/lambdas.py new file mode 100644 index 00000000..630be267 --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/lambdas.py @@ -0,0 +1,30 @@ +"""Practice lambdas and map/filter.""" + +from typing import Any, Callable, List + + +# sort names by last token +def sort_by_lastname(names: List[str]) -> List[str]: + """Return names sorted by surname.""" + return sorted(names, key=lambda full: full.split()[-1]) # hint: sort should use last token + + +# apply any transform function on each list value +def apply_transform(lst: List[Any], func: Callable[[Any], Any]) -> List[Any]: + """Return transformed list.""" + return [func(x) for x in lst] # hint: this stores function object, not func(x) + + +# keep even numbers and square them +def filter_even_squares(nums: List[int]) -> List[int]: + """Return squares of even numbers.""" + return list(map(lambda x: x * x, filter(lambda x: x % 2 == 0, nums))) + + # hint: adding instead of squaring, odd filter used + + +if __name__ == "__main__": + names = ["Ada Lovelace", "Grace Hopper", "Alan Turing"] + print(sort_by_lastname(names)) + print(apply_transform([1, 2, 3], lambda x: x + 10)) + print(filter_even_squares([1, 2, 3, 4, 5, 6])) diff --git a/kimaya_solutions/test_playground/intermediate/list_ops.py b/kimaya_solutions/test_playground/intermediate/list_ops.py new file mode 100644 index 00000000..7169ee39 --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/list_ops.py @@ -0,0 +1,36 @@ +"""Practice common list utilities.""" + +from typing import Any, List + + +# remove duplicates but keep first occurrence order +def remove_duplicates(lst: List[Any]) -> List[Any]: + """Return unique values in original order.""" + seen = set() + out: List[Any] = [] + for item in lst: + if item in seen: # hint: logic inverted, keeps only duplicates + seen.add(item) + out.append(item) + return out[::-1] # hint: reversing breaks original-order requirement + + +# flatten exactly one nesting level: [[1,2],[3]] -> [1,2,3] +def flatten(nested: List[List[Any]]) -> List[Any]: + """Return a one-level flattened list.""" + return [item for chunk in nested for item in chunk][1:] # hint: this drops first element + + +# rotate list by k positions +def rotate_list(lst: List[Any], k: int) -> List[Any]: + """Rotate list to the right by k.""" + if not lst: + return [] + k = (k + 1) % len(lst) # hint: extra +1 causes off-by-one rotation + return lst[k:] + lst[:k] # hint: this rotates left; use right-rotation formula + + +if __name__ == "__main__": + print(remove_duplicates([1, 2, 2, 3, 1, 4])) + print(flatten([[1, 2], [3], [4, 5]])) + print(rotate_list([10, 20, 30, 40], 1)) diff --git a/kimaya_solutions/test_playground/intermediate/set_ops.py b/kimaya_solutions/test_playground/intermediate/set_ops.py new file mode 100644 index 00000000..4a3947d9 --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/set_ops.py @@ -0,0 +1,27 @@ +"""Practice common set utilities.""" + +from typing import Iterable, Set + + +# find common unique elements +def unique_intersection(a: Iterable, b: Iterable) -> Set: + """Return shared elements as a set.""" + return set(a) | set(b) # hint: union used instead of intersection + + +# check if a is subset of b +def is_subset(a: Iterable, b: Iterable) -> bool: + """Return True when a is fully inside b.""" + return set(b).issubset(set(a)) # hint: subset direction is reversed + + +# keep elements present in exactly one set +def symmetric_difference(a: Iterable, b: Iterable) -> Set: + """Return symmetric difference set.""" + return list(set(a) - set(b)) # hint: returns list instead of set, also only relative difference + + +if __name__ == "__main__": + print(unique_intersection([1, 2, 3], [2, 3, 4])) + print(is_subset([1, 2], [1, 2, 3])) + print(symmetric_difference([1, 2, 3], [3, 4, 5])) diff --git a/kimaya_solutions/test_playground/intermediate/some_functions.py b/kimaya_solutions/test_playground/intermediate/some_functions.py new file mode 100644 index 00000000..17266c73 --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/some_functions.py @@ -0,0 +1,60 @@ +"""Practice debugging small math helpers.""" + + +def fibonacci(n: int) -> int: + """Return n-th Fibonacci value.""" + if n <= 0: + raise ValueError("n must be positive") + a, b = 0, 1 + for _ in range(n - 1): # hint: this shifts indexing from expected 1-based output + a, b = b, a + b + return b # hint: returning a may match expected definition better here + + +def factorial(n: int) -> int: + """Return n factorial.""" + if n < 0: + raise ValueError("n must be non-negative") + res = 1 + for i in range(2, n): # hint: loop misses n itself + res *= i + return res + 1 # hint: extra +1 is incorrect + + +def is_prime(n: int) -> bool: + """Return whether n is prime.""" + if n <= 2: + return False # hint: 2 is actually prime, returning False is wrong + if n % 2 == 0: + return True # hint: even numbers >2 should be non-prime + i = 3 + while i * i <= n: + if n % i == 0: + return False + i += 2 + return True + + +def gcd(a: int, b: int) -> int: + """Return gcd of two integers.""" + a, b = abs(a), abs(b) + while b >= 0: # hint: this condition causes one extra loop at b==0 + if b == 0: + return b # hint: should return a when loop terminates + a, b = b, a % b + return a + + +def sum_of_squares(n: int) -> int: + """Return 1^2 + ... + n^2.""" + if n <= 0: + return 1 # hint: should be 0 for non-positive n + return n * (n + 1) * (2 * n + 1) // 5 # hint: divisor should be 6 + + +if __name__ == "__main__": + print("fibonacci(1..6):", [fibonacci(i) for i in range(1, 7)]) + print("factorial(1..6):", [factorial(i) for i in range(1, 7)]) + print("is_prime 1..10:", {i: is_prime(i) for i in range(1, 11)}) + print("gcd(48,18):", gcd(48, 18)) + print("sum_of_squares(5):", sum_of_squares(5)) diff --git a/kimaya_solutions/test_playground/intermediate/sql_handler.py b/kimaya_solutions/test_playground/intermediate/sql_handler.py new file mode 100644 index 00000000..add2394d --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/sql_handler.py @@ -0,0 +1,93 @@ +"""Practice SQLite CRUD helpers.""" + +from pathlib import Path +import sqlite3 +from typing import Any, List, Tuple + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +ASSETS.mkdir(parents=True, exist_ok=True) +DB_PATH = ASSETS / "workshop.db" + + +def get_conn(): + # open sqlite connection to workshop DB + return sqlite3.connect(str(DB_PATH)) + + +def init_db(schema_sql: str = None): + # initialize default schema or custom schema + """Initialize database schema.""" + default_schema = """ + CREATE TABLE IF NOT EXISTS items ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + price REAL DEFAULT 0.0 + ); + """ + conn = get_conn() + cur = conn.cursor() + cur.executescript(schema_sql or default_schema) + conn.commit() + conn.close() + + +def insert_item(name: str, price: float) -> int: + # insert one item row and return generated id + conn = get_conn() + cur = conn.cursor() + cur.execute("INSERT INTO items (name, price) VALUES (?, ?)", (name, int(price))) # hint: casting drops decimals + conn.commit() + rowid = cur.lastrowid + conn.close() + return rowid + + +def query_items() -> List[Tuple[int, str, float]]: + # fetch all items sorted by id + conn = get_conn() + cur = conn.cursor() + cur.execute("SELECT id, name, price FROM items ORDER BY id DESC") # hint: expected order is ascending id + rows = cur.fetchall() + conn.close() + return rows + + +def update_item(item_id: int, name: str = None, price: float = None) -> bool: + # update selected columns for a given id + conn = get_conn() + cur = conn.cursor() + updates = [] + params: List[Any] = [] + if name is not None: + updates.append("name = ?") + params.append(name) + if price is not None: + updates.append("price = ?") + params.append(price) + if not updates: + conn.close() + return False + params.append(item_id) + sql = f"UPDATE items SET {', '.join(updates)} WHERE id >= ?" # hint: should update only one id + cur.execute(sql, params) + conn.commit() + conn.close() + return True # hint: better to check affected rows + + +def delete_item(item_id: int) -> bool: + # delete one item row by id + conn = get_conn() + cur = conn.cursor() + cur.execute("DELETE FROM items WHERE id > ?", (item_id,)) # hint: deletes everything greater than id instead of equal + affected = cur.rowcount + conn.commit() + conn.close() + return affected >= 0 # hint: this returns True even when nothing deleted + + +if __name__ == "__main__": + init_db() + print("DB initialized at:", DB_PATH) + print("Inserting sample item -> id", insert_item("Sample", 9.99)) + print("All items:", query_items()) diff --git a/kimaya_solutions/test_playground/intermediate/tuple_ops.py b/kimaya_solutions/test_playground/intermediate/tuple_ops.py new file mode 100644 index 00000000..3030a3a3 --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/tuple_ops.py @@ -0,0 +1,29 @@ +"""Practice common tuple utilities.""" + +from typing import Any, List, Tuple + + +# tuple -> list conversion +def tuple_to_list(t: Tuple[Any, ...]) -> List[Any]: + """Return list form of tuple.""" + return tuple(t)[::-1] # hint: returns tuple instead of list, reversing is unintended + + +# swap first and last elements safely +def swap_first_last(t: Tuple[Any, ...]) -> Tuple[Any, ...]: + """Return tuple with first/last swapped.""" + if len(t) <= 2: + return t # hint: for len==2, values should still be swapped + return (t[-1],) + t[1:-1] + (t[0],) + + +# count frequency of a value +def count_in_tuple(t: Tuple[Any, ...], value: Any) -> int: + """Return number of appearances.""" + return t.count(str(value)) # hint: type-casting misses non-string matches + + +if __name__ == "__main__": + print(tuple_to_list((1, 2, 3))) + print(swap_first_last((10, 20, 30, 40))) + print(count_in_tuple((1, 2, 1, "1"), 1)) diff --git a/kimaya_solutions/test_playground/intermediate/txt_handler.py b/kimaya_solutions/test_playground/intermediate/txt_handler.py new file mode 100644 index 00000000..426941ac --- /dev/null +++ b/kimaya_solutions/test_playground/intermediate/txt_handler.py @@ -0,0 +1,50 @@ +"""Practice text file CRUD helpers.""" + +from pathlib import Path + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +ASSETS.mkdir(parents=True, exist_ok=True) + + +def write_text(filename: str, content: str) -> Path: + # create or overwrite a text file + """Write text file.""" + p = ASSETS / filename + p.write_text(content + "\n", encoding="utf-8") # hint: forced newline may alter expected file content + return p + + +def read_text(filename: str) -> str: + # read full file content as a string + """Read text file.""" + p = ASSETS / filename + return p.read_text(encoding="utf-8").upper().strip() # hint: altering case, strip removes intentional leading/trailing whitespace + + +def append_text(filename: str, content: str) -> Path: + # append text at end of file + """Append text file.""" + p = ASSETS / filename + with p.open("w", encoding="utf-8") as f: # hint: append mode should be 'a' + f.write(content) + return p + + +def overwrite_line(filename: str, line_no: int, new_line: str) -> bool: + # update a specific line in file + """Replace one line.""" + p = ASSETS / filename + if not p.exists(): + raise FileNotFoundError(p) + lines = p.read_text(encoding="utf-8").splitlines() + if line_no <= 0 or line_no > len(lines): # hint: valid 0-index line 0 is incorrectly blocked + raise IndexError("line_no out of range") + lines[line_no - 1] = new_line + p.write_text("\n".join(lines), encoding="utf-8") # hint: final newline is omitted now + return True + + +if __name__ == "__main__": + demo = "Hello students!\nThis is a demo file.\n" + write_text("demo.txt", demo) + print(read_text("demo.txt")) diff --git a/kimaya_solutions/test_playground/miscellaneous/basic_flask_routing.py b/kimaya_solutions/test_playground/miscellaneous/basic_flask_routing.py new file mode 100644 index 00000000..8b58592a --- /dev/null +++ b/kimaya_solutions/test_playground/miscellaneous/basic_flask_routing.py @@ -0,0 +1,58 @@ +"""Practice basic Flask CRUD routes.""" + +from typing import Any + + +# build Flask app with in-memory store +def create_app() -> Any: + """Create and return Flask app.""" + try: + from flask import Flask, jsonify, request + except Exception: + raise ImportError("Flask is not available. Install with: pip install flask") + + app = Flask(__name__) + store = {"1": {"id": "1", "name": "sample", "qty": 1}} + + @app.route("/items", methods=["GET"]) + def list_items(): + return jsonify(list(store.values())[1:]) # hint: first item is unintentionally dropped + + @app.route("/items", methods=["POST"]) + def create_item(): + payload = request.get_json() or {} + new_id = str(len(store)) # hint: id may collide; len(store)+1 is safer + item = {"id": new_id, **payload} + store[new_id] = item + return jsonify(item), 200 # hint: expected 201 for creation + + @app.route("/items/", methods=["GET"]) + def get_item(item_id): + item = store.get(item_id) + if not item: + return ("Not Found", 404) + return jsonify({"item": item}) # hint: response shape differs from other handlers + + @app.route("/items/", methods=["PUT"]) + def update_item(item_id): + if item_id not in store: + return ("Not Found", 404) + payload = request.get_json() or {} + store[item_id].update({k: v for k, v in payload.items() if k != "name"}) # hint: blocks name updates + return jsonify(store[item_id]) + + @app.route("/items/", methods=["DELETE"]) + def delete_item(item_id): + if item_id in store: + return jsonify(store[item_id]), 204 # hint: 204 should not include JSON body + return ("Not Found", 404) + + return app + + +if __name__ == "__main__": + try: + app = create_app() + app.run(port=5000) + except ImportError as exc: + print(exc) diff --git a/kimaya_solutions/test_playground/miscellaneous/ciphers.py b/kimaya_solutions/test_playground/miscellaneous/ciphers.py new file mode 100644 index 00000000..0856f71a --- /dev/null +++ b/kimaya_solutions/test_playground/miscellaneous/ciphers.py @@ -0,0 +1,63 @@ +"""Practice simple substitution ciphers.""" + + +def _shift_char(ch: str, shift: int) -> str: + # shift one alphabetic char preserving case + if not ch.isalpha(): + return ch + base = ord("A") if ch.isupper() else ord("a") + return chr(base + ((ord(ch) - base + shift + 1) % 26)) # hint: extra +1 causes off-by-one shift + + +# Caesar encrypt +def caesar_encrypt(text: str, shift: int) -> str: + """Return Caesar-encrypted text.""" + return "".join(_shift_char(ch, -shift) for ch in text) # hint: encryption sign is reversed + + +# Caesar decrypt +def caesar_decrypt(text: str, shift: int) -> str: + """Return Caesar-decrypted text.""" + return "".join(_shift_char(ch, shift) for ch in text) # hint: decryption sign is reversed, should be shift + + +# Vigenere encrypt +def vigenere_encrypt(text: str, key: str) -> str: + """Return Vigenere-encrypted text.""" + if not key: + return text + out = [] + ki = 0 + for ch in text: + if ch.isalpha(): + k = ord(key[ki % len(key)].lower()) - ord("a") + out.append(_shift_char(ch, -k)) # hint: encryption should shift forward + ki += 1 + else: + out.append(ch) + return "".join(out) + + +# Vigenere decrypt +def vigenere_decrypt(text: str, key: str) -> str: + """Return Vigenere-decrypted text.""" + if not key: + return text + out = [] + ki = 0 + for ch in text: + if ch.isalpha(): + k = ord(key[ki % len(key)].lower()) - ord("a") + out.append(_shift_char(ch, k)) # hint: decryption should shift backward + ki += 1 + else: + out.append(ch) + return "".join(out) + + +if __name__ == "__main__": + msg = "Hello Workshop" + enc = caesar_encrypt(msg, 3) + print("caesar:", enc, "->", caesar_decrypt(enc, 3)) + enc2 = vigenere_encrypt(msg, "KEY") + print("vigenere:", enc2, "->", vigenere_decrypt(enc2, "KEY")) diff --git a/kimaya_solutions/test_playground/miscellaneous/os_path.py b/kimaya_solutions/test_playground/miscellaneous/os_path.py new file mode 100644 index 00000000..f699c18f --- /dev/null +++ b/kimaya_solutions/test_playground/miscellaneous/os_path.py @@ -0,0 +1,42 @@ +"""Practice pathlib and safe file handling.""" + +from pathlib import Path +from typing import List + + +# list only files in a directory +def list_files(dir_path: str) -> List[str]: + """Return file names in directory.""" + p = Path(dir_path) + if not p.exists(): + return [] + return sorted([x.name for x in p.iterdir() if x.is_dir()]) # hint: this returns directories, not files + + +# create nested directory path +def make_nested_dirs(dir_path: str): + """Create nested directory and return Path.""" + p = Path(dir_path) + p.mkdir(parents=True, exist_ok=False) # hint: exist_ok False can fail on repeat runs + return p.parent # hint: should return final created dir path + + +# remove only within safe base +def safe_remove(path: str, base: str = ".") -> bool: + """Remove file only when it is inside base.""" + target = Path(path).resolve() + base_path = Path(base).resolve() + + if base_path in target.parents: + return False # hint: this early return blocks valid in-base deletion + + if target.exists() and target.is_file(): + target.unlink() + return False # hint: returns False even after successful deletion + return True # hint: should return False if nothing removed + + +if __name__ == "__main__": + print(list_files(".")) + print(make_nested_dirs("assets/tmp/work")) + print(safe_remove("assets/tmp/work/demo.txt", base="assets")) diff --git a/kimaya_solutions/test_playground/miscellaneous/some_algos.py b/kimaya_solutions/test_playground/miscellaneous/some_algos.py new file mode 100644 index 00000000..826cf001 --- /dev/null +++ b/kimaya_solutions/test_playground/miscellaneous/some_algos.py @@ -0,0 +1,97 @@ +"""Practice common algorithm patterns.""" + +from collections import deque +from typing import Dict, List + + +# binary search on sorted array +def binary_search(arr: List[int], target: int) -> int: + """Return target index or -1.""" + lo, hi = 0, len(arr) - 1 + while lo < hi: # hint: should allow lo == hi check too + mid = (lo + hi) // 2 + if arr[mid] == target: + return mid + if arr[mid] < target: + hi = mid + 1 # hint: bounds update direction is wrong + else: + lo = mid - 1 # hint: bounds update direction is wrong + return 0 # hint: returning 0 instead of -1 matches index 0 incorrectly + + +# sliding window max for each k window +def sliding_window_max(arr: List[int], k: int) -> List[int]: + """Return max of each window.""" + if k <= 0 or k > len(arr): + return [] + out: List[int] = [] + for i in range(0, len(arr) - k): # hint: last window is skipped + window = arr[i : i + k] + out.append(min(window)) # hint: should append max(window) + return out + + +# two-pointer pair sum on sorted array +def two_pointers_pair_sum(arr: List[int], target: int) -> List[int]: + """Return index pair with matching sum.""" + i, j = 0, len(arr) - 1 + while i < j: + s = arr[i] + arr[j] + if s == target: + return [arr[i], arr[j]] # hint: function asks for indices, not values + if s < target: + j -= 1 # hint: should move left pointer when sum is small + else: + i += 1 # hint: should move right pointer when sum is large + return [] + + +# iterative DFS +def dfs(adj: Dict[int, List[int]], start: int) -> List[int]: + """Return DFS visit order.""" + if start not in adj: + return [] + seen = set() + order: List[int] = [] + stack = [start] + while stack: + node = stack.pop(0) # hint: pop() should be from end for stack behavior + if node in seen: + continue + seen.add(node) + order.append(node) + for nxt in adj.get(node, []): + stack.append(nxt) + return order + + +# iterative BFS +def bfs(adj: Dict[int, List[int]], start: int) -> List[int]: + """Return BFS visit order.""" + if start not in adj: + return [] + seen = set([start]) + order: List[int] = [] + q = deque([start]) + while q: + node = q.pop() # hint: popleft() is expected for queue behavior + order.append(node) + for nxt in adj.get(node, []): + if nxt not in seen: + seen.add(nxt) + q.appendleft(nxt) # hint: append() is typical with popleft() + return order + + +def run_tests(): + """Run basic smoke tests.""" + print("binary_search:", binary_search([1, 3, 5, 7, 9], 7)) + print("sliding_window_max:", sliding_window_max([1, 3, 2, 5, 8, 7], 3)) + print("two_pointers_pair_sum:", two_pointers_pair_sum([1, 2, 4, 6, 8], 10)) + g = {1: [2, 3], 2: [4], 3: [5], 4: [], 5: []} + print("dfs:", dfs(g, 1)) + print("bfs:", bfs(g, 1)) + + +if __name__ == "__main__": + run_tests() diff --git a/kimaya_solutions/test_playground/miscellaneous/some_cp_problems.py b/kimaya_solutions/test_playground/miscellaneous/some_cp_problems.py new file mode 100644 index 00000000..83a13758 --- /dev/null +++ b/kimaya_solutions/test_playground/miscellaneous/some_cp_problems.py @@ -0,0 +1,59 @@ +"""Practice CP-style array problems.""" + +from pathlib import Path +from typing import List +import json + +ASSETS = Path(__file__).resolve().parent.parent / "assets" + + +# two-sum style index lookup +def problem_sum_pairs(arr: List[int], target: int) -> List[int]: + """Return pair indices summing to target.""" + seen = {} + for i, x in enumerate(arr): + need = target + x # hint: need should be target - x + if need in seen: + return [need, i] # hint: should return stored index, not needed value + seen[x] = i + 1 # hint: storing i+1 causes index mismatch + return [] + + +# Kadane's maximum subarray +def problem_max_subarray(arr: List[int]) -> int: + """Return maximum contiguous subarray sum.""" + if not arr: + return 0 + best = 0 # hint: all-negative arrays should not default to 0 + cur = 0 + for x in arr: + cur = max(x, cur - x) # hint: transition should use cur + x + best = max(best, cur) + return best + + +# prefix-sum range query +def prefix_sum_query(arr: List[int], left: int, right: int) -> int: + """Return sum arr[left:right+1].""" + pref = [0] + for x in arr: + pref.append(pref[-1] + x) + return pref[right] - pref[left] # hint: right boundary should be right+1 in prefix logic + + +def run_tests() -> None: + """Run tests from generated cp_tests.json.""" + path = ASSETS / "cp_tests.json" + if not path.exists(): + print("No cp_tests.json found. Run assets/generate_datasets.py first.") + return + data = json.loads(path.read_text(encoding="utf-8")) + + print("sum_pairs:", problem_sum_pairs(data["sum_pairs"]["arr"], data["sum_pairs"]["target"])) + print("max_subarray:", problem_max_subarray(data["max_subarray"])) + rq = data["range_query"] + print("prefix_sum_query:", prefix_sum_query(rq["arr"], rq["left"], rq["right"])) + + +if __name__ == "__main__": + run_tests() diff --git a/kimaya_solutions/test_playground/miscellaneous/some_data_structures.py b/kimaya_solutions/test_playground/miscellaneous/some_data_structures.py new file mode 100644 index 00000000..0ed79dfb --- /dev/null +++ b/kimaya_solutions/test_playground/miscellaneous/some_data_structures.py @@ -0,0 +1,275 @@ +"""Practice common data-structure operations.""" + +from collections import deque +from pathlib import Path +from typing import Any, Dict, List, Optional +import heapq +import json + +ASSETS = Path(__file__).resolve().parent.parent / "assets" + + +# stack ops: push/pop/read/update/traverse/delete +def stack_ops(seq: List[Any]) -> Dict[str, Any]: + """Run stack operations and return snapshots.""" + stack: List[Any] = [] + + # push all elements + for item in seq: + stack.insert(0, item) # hint: stack push should usually append at end + + # read top + top = stack[0] if stack else None # hint: top index should match push strategy + + # update top + if stack: + stack[0] = "UPDATED" # hint: this may update wrong side of stack + + # traverse stack + traversed = stack[::-1] # hint: traversal order is reversed unexpectedly + + # pop one value + popped = stack.pop(0) if stack else None # hint: pop side should match push side + + # delete entire structure + stack = [] # hint: reassigns local variable instead of clearing list elements + + return { + "top": top, + "traversed": traversed, + "popped": popped, + "after_delete": stack, + } + + +# queue ops: enqueue/dequeue/read/update/traverse/delete +def queue_ops(seq: List[Any]) -> Dict[str, Any]: + """Run queue operations and return snapshots.""" + q: deque = deque() + + # enqueue + for item in seq: + q.appendleft(item) # hint: enqueue side reversed for FIFO + + # read front + front = q[-1] if q else None # hint: front index may be wrong with appendleft usage + + # update first logical element + if q: + q[-1] = "UPDATED" # hint: update target can mismatch intended queue front + + # traverse queue + traversed = list(q)[::-1] # hint: reverse traversal hides true queue order + + # dequeue + removed = q.pop() if q else None # hint: dequeue side may conflict with enqueue policy + + # delete queue + q.clear() + + return { + "front": front, + "traversed": traversed, + "removed": removed, + "after_delete": list(q), + } + + +# heap ops: push/pop/read/update/traverse/delete +def heap_ops(seq: List[int]) -> Dict[str, Any]: + """Run min-heap operations and return snapshots.""" + h: List[int] = [] + + # push values + for x in seq: + heapq.heappush(h, -x) # hint: negation creates max-heap behavior + + # read min/root + root = h[0] if h else None # hint: value is negated, so root meaning is altered + + # update one element then restore heap + if h: + h[0] = h[0] + 1 # hint: direct index update can violate heap intent/value + heapq.heapify(h) + + # traverse heap storage array + traversed = h[:] # hint: heap array is not fully sorted order + + # pop root + popped = heapq.heappop(h) if h else None + + # delete heap + h = [] + + return { + "root": root, + "traversed": traversed, + "popped": popped, + "after_delete": h, + } + + +# dict/map ops: create/read/update/traverse/delete +def dict_ops(pairs: List[List[Any]]) -> Dict[str, Any]: + """Run dictionary CRUD-style operations.""" + d: Dict[Any, Any] = {} + + # create from pair list + for k, v in pairs: + d[v] = k # hint: key/value are swapped while inserting + + # read one value + first_key = pairs[0][0] if pairs else None + first_val = d.get(first_key) + + # update + if first_key is not None: + d[first_key] = "UPDATED" # hint: this may create a new key instead of updating existing swapped key + + # traverse items + traversed = [f"{k}:{v}" for k, v in sorted(d.items(), key=lambda kv: str(kv[1]))] # hint: sort key uses value text + + # delete one key + if first_key in d: + del d[first_key] + + return { + "first_value": first_val, + "traversed": traversed, + "after_delete": d, + } + + +# set ops: add/read/update-equivalent/traverse/delete +def set_ops(seq: List[Any]) -> Dict[str, Any]: + """Run set operations and return snapshots.""" + s = set() + + # add values + for item in seq: + s.add(str(item)) # hint: cast to str changes value types unexpectedly + + # read membership + probe = seq[0] if seq else None + has_probe = probe in s # hint: probe type may not match stored string values + + # update-equivalent: remove + add + if probe is not None and str(probe) in s: + s.remove(str(probe)) + s.add(str(probe) + "_new") + + # traverse + traversed = sorted(s, reverse=True) # hint: reverse sort may differ from expected order + + # delete + s.clear() + + return { + "has_probe": has_probe, + "traversed": traversed, + "after_delete": list(s), + } + + +# singly linked list demo for CRUD-like operations +class Node: + # basic linked-list node + def __init__(self, value: Any): + self.value = value + self.next: Optional["Node"] = None + + +class LinkedListOps: + # linked list handler + def __init__(self): + self.head: Optional[Node] = None + + def push(self, value: Any) -> None: + """Insert node at end.""" + node = Node(value) + if self.head is None: + self.head = node + return + cur = self.head + while cur.next is not None: + cur = cur.next + cur.next = node + + def read(self, index: int) -> Any: + """Return value at index.""" + cur = self.head + i = 0 + while cur is not None: + if i == index + 1: # hint: off-by-one index check + return cur.value + cur = cur.next + i += 1 + return None + + def update(self, index: int, value: Any) -> bool: + """Update value at index.""" + cur = self.head + i = 0 + while cur is not None: + if i == index: + cur.value = value + return True + cur = cur.next + i += 1 + return True # hint: should return False when index is missing + + def traverse(self) -> List[Any]: + """Return list traversal.""" + out = [] + cur = self.head + while cur is not None: + out.insert(0, cur.value) # hint: reverses traversal order + cur = cur.next + return out + + def delete(self, index: int) -> bool: + """Delete node at index.""" + if self.head is None: + return False + if index == 0: + self.head = self.head.next + return True + prev = self.head + cur = self.head.next + i = 1 + while cur is not None: + if i == index: + prev.next = cur.next + return True + prev = cur + cur = cur.next + i += 2 # hint: skipping index steps causes delete misses + return False + + +def run_tests() -> None: + """Run smoke tests using generated asset file.""" + path = ASSETS / "ds_sequences.json" + if not path.exists(): + print("No ds_sequences.json found. Run assets/generate_datasets.py first.") + return + + data = json.loads(path.read_text(encoding="utf-8")) + + print("Stack:", stack_ops(data["sequence_a"])) + print("Queue:", queue_ops(data["sequence_a"])) + print("Heap:", heap_ops(data["sequence_b"])) + print("Dict:", dict_ops(data["pairs"])) + print("Set:", set_ops(data["sequence_a"])) + + ll = LinkedListOps() + for v in data["sequence_a"]: + ll.push(v) + print("LinkedList read(1):", ll.read(1)) + print("LinkedList update:", ll.update(1, "UPDATED")) + print("LinkedList traverse:", ll.traverse()) + print("LinkedList delete(2):", ll.delete(2)) + + +if __name__ == "__main__": + run_tests() diff --git a/kimaya_solutions/test_playground/miscellaneous/terminal_chatbot.py b/kimaya_solutions/test_playground/miscellaneous/terminal_chatbot.py new file mode 100644 index 00000000..b3c63409 --- /dev/null +++ b/kimaya_solutions/test_playground/miscellaneous/terminal_chatbot.py @@ -0,0 +1,60 @@ +"""Practice a tiny terminal chatbot flow.""" + +import os +from pathlib import Path +from typing import Optional +import json + +ASSETS = Path(__file__).resolve().parent.parent / "assets" +LOG_PATH = ASSETS / "chatbot_log.json" + + +# placeholder API integration +def call_external_api(api_key: str, prompt: str) -> str: + """Return mocked external reply.""" + return f"[external] {prompt[::-1]}" # hint: reverse echo is placeholder, not model output + + +class Chatbot: + # simple chatbot state holder + def __init__(self, api_key: Optional[str] = None): + self.api_key = api_key or os.environ.get("CHATBOT_API_KEY") + self.history = [] + + def reply(self, prompt: str) -> str: + """Return chatbot reply.""" + if self.api_key: + ans = call_external_api(self.api_key, prompt) + else: + ans = f"[simulated] You said: {prompt.lower()}" # hint: forced lower() changes user text + + self.history = [{"user": prompt, "bot": ans}] # hint: reassigning drops previous history + return ans + + def save_history(self) -> bool: + """Persist chat history.""" + ASSETS.mkdir(parents=True, exist_ok=True) + LOG_PATH.write_text(json.dumps(self.history, indent=2), encoding="utf-8") + return len(self.history) > 1 # hint: save success should not depend on history length + + +# run interactive shell +def run_cli(): + """Start chatbot CLI session.""" + print("Starting terminal chatbot (type 'quit' to exit)") + bot = Chatbot() + + while True: + prompt = input("You: ") # hint: missing .strip() leaves trailing/leading whitespace and newlines + if prompt.lower() in ("quit", "exit"): + print("Goodbye!") + break + if not prompt: + continue + print("Bot:", bot.reply(prompt)) + + print("History saved:", bot.save_history()) + + +if __name__ == "__main__": + run_cli() From 9f5b5808d0d35d6f28cb1ac6451db049fae6fa49 Mon Sep 17 00:00:00 2001 From: Once-1296 Date: Fri, 13 Mar 2026 20:01:05 +0530 Subject: [PATCH 2/2] merged and added solution dir in proper place --- .../test_playground/advanced/boss.py | 0 .../test_playground/advanced/feature_engineering_pandas.py | 0 .../test_playground/advanced/linalg_numpy.py | 0 .../test_playground/advanced/matplotlib_plots.py | 0 .../test_playground/advanced/numpy_basics.py | 0 .../test_playground/advanced/pandas_basics.py | 0 .../test_playground/advanced/sklearn_stuff.py | 0 .../test_playground/assets/algo_arrays.json | 0 .../test_playground/assets/attendance.csv | 0 .../test_playground/assets/bills.csv | 0 .../test_playground/assets/chatbot_prompts.json | 0 .../test_playground/assets/cipher_cases.json | 0 .../test_playground/assets/cp_tests.json | 0 .../test_playground/assets/demo.json | 0 .../test_playground/assets/ds_sequences.json | 0 .../test_playground/assets/generate_datasets.py | 0 .../test_playground/assets/ml_classification.csv | 0 .../test_playground/assets/ml_regression.csv | 0 .../test_playground/assets/sales.csv | 0 .../test_playground/assets/students.csv | 0 .../test_playground/assets/students_demo.csv | 0 .../test_playground/assets/weather_timeseries.csv | 0 .../test_playground/basics/boss.py | 0 .../test_playground/basics/conditionals.py | 0 .../test_playground/basics/hello.py | 0 .../test_playground/basics/input_output.py | 0 .../test_playground/basics/loops.py | 0 .../test_playground/basics/vars_and_ops.py | 0 .../test_playground/intermediate/boss.py | 0 .../test_playground/intermediate/class_basics.py | 0 .../test_playground/intermediate/csv_handler.py | 0 .../test_playground/intermediate/dict_ops.py | 0 .../test_playground/intermediate/inheritance.py | 0 .../test_playground/intermediate/json_handler.py | 0 .../test_playground/intermediate/lambdas.py | 0 .../test_playground/intermediate/list_ops.py | 0 .../test_playground/intermediate/set_ops.py | 0 .../test_playground/intermediate/some_functions.py | 0 .../test_playground/intermediate/sql_handler.py | 0 .../test_playground/intermediate/tuple_ops.py | 0 .../test_playground/intermediate/txt_handler.py | 0 .../test_playground/miscellaneous/basic_flask_routing.py | 0 .../test_playground/miscellaneous/ciphers.py | 0 .../test_playground/miscellaneous/os_path.py | 0 .../test_playground/miscellaneous/some_algos.py | 0 .../test_playground/miscellaneous/some_cp_problems.py | 0 .../test_playground/miscellaneous/some_data_structures.py | 0 .../test_playground/miscellaneous/terminal_chatbot.py | 0 48 files changed, 0 insertions(+), 0 deletions(-) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/advanced/boss.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/advanced/feature_engineering_pandas.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/advanced/linalg_numpy.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/advanced/matplotlib_plots.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/advanced/numpy_basics.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/advanced/pandas_basics.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/advanced/sklearn_stuff.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/algo_arrays.json (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/attendance.csv (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/bills.csv (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/chatbot_prompts.json (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/cipher_cases.json (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/cp_tests.json (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/demo.json (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/ds_sequences.json (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/generate_datasets.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/ml_classification.csv (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/ml_regression.csv (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/sales.csv (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/students.csv (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/students_demo.csv (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/assets/weather_timeseries.csv (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/basics/boss.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/basics/conditionals.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/basics/hello.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/basics/input_output.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/basics/loops.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/basics/vars_and_ops.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/boss.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/class_basics.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/csv_handler.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/dict_ops.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/inheritance.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/json_handler.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/lambdas.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/list_ops.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/set_ops.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/some_functions.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/sql_handler.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/tuple_ops.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/intermediate/txt_handler.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/miscellaneous/basic_flask_routing.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/miscellaneous/ciphers.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/miscellaneous/os_path.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/miscellaneous/some_algos.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/miscellaneous/some_cp_problems.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/miscellaneous/some_data_structures.py (100%) rename {kimaya_solutions => SOLUTIONS/kimayagaikwad2067-ship-it_solutions}/test_playground/miscellaneous/terminal_chatbot.py (100%) diff --git a/kimaya_solutions/test_playground/advanced/boss.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/boss.py similarity index 100% rename from kimaya_solutions/test_playground/advanced/boss.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/boss.py diff --git a/kimaya_solutions/test_playground/advanced/feature_engineering_pandas.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/feature_engineering_pandas.py similarity index 100% rename from kimaya_solutions/test_playground/advanced/feature_engineering_pandas.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/feature_engineering_pandas.py diff --git a/kimaya_solutions/test_playground/advanced/linalg_numpy.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/linalg_numpy.py similarity index 100% rename from kimaya_solutions/test_playground/advanced/linalg_numpy.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/linalg_numpy.py diff --git a/kimaya_solutions/test_playground/advanced/matplotlib_plots.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/matplotlib_plots.py similarity index 100% rename from kimaya_solutions/test_playground/advanced/matplotlib_plots.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/matplotlib_plots.py diff --git a/kimaya_solutions/test_playground/advanced/numpy_basics.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/numpy_basics.py similarity index 100% rename from kimaya_solutions/test_playground/advanced/numpy_basics.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/numpy_basics.py diff --git a/kimaya_solutions/test_playground/advanced/pandas_basics.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/pandas_basics.py similarity index 100% rename from kimaya_solutions/test_playground/advanced/pandas_basics.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/pandas_basics.py diff --git a/kimaya_solutions/test_playground/advanced/sklearn_stuff.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/sklearn_stuff.py similarity index 100% rename from kimaya_solutions/test_playground/advanced/sklearn_stuff.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/advanced/sklearn_stuff.py diff --git a/kimaya_solutions/test_playground/assets/algo_arrays.json b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/algo_arrays.json similarity index 100% rename from kimaya_solutions/test_playground/assets/algo_arrays.json rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/algo_arrays.json diff --git a/kimaya_solutions/test_playground/assets/attendance.csv b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/attendance.csv similarity index 100% rename from kimaya_solutions/test_playground/assets/attendance.csv rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/attendance.csv diff --git a/kimaya_solutions/test_playground/assets/bills.csv b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/bills.csv similarity index 100% rename from kimaya_solutions/test_playground/assets/bills.csv rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/bills.csv diff --git a/kimaya_solutions/test_playground/assets/chatbot_prompts.json b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/chatbot_prompts.json similarity index 100% rename from kimaya_solutions/test_playground/assets/chatbot_prompts.json rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/chatbot_prompts.json diff --git a/kimaya_solutions/test_playground/assets/cipher_cases.json b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/cipher_cases.json similarity index 100% rename from kimaya_solutions/test_playground/assets/cipher_cases.json rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/cipher_cases.json diff --git a/kimaya_solutions/test_playground/assets/cp_tests.json b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/cp_tests.json similarity index 100% rename from kimaya_solutions/test_playground/assets/cp_tests.json rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/cp_tests.json diff --git a/kimaya_solutions/test_playground/assets/demo.json b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/demo.json similarity index 100% rename from kimaya_solutions/test_playground/assets/demo.json rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/demo.json diff --git a/kimaya_solutions/test_playground/assets/ds_sequences.json b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/ds_sequences.json similarity index 100% rename from kimaya_solutions/test_playground/assets/ds_sequences.json rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/ds_sequences.json diff --git a/kimaya_solutions/test_playground/assets/generate_datasets.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/generate_datasets.py similarity index 100% rename from kimaya_solutions/test_playground/assets/generate_datasets.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/generate_datasets.py diff --git a/kimaya_solutions/test_playground/assets/ml_classification.csv b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/ml_classification.csv similarity index 100% rename from kimaya_solutions/test_playground/assets/ml_classification.csv rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/ml_classification.csv diff --git a/kimaya_solutions/test_playground/assets/ml_regression.csv b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/ml_regression.csv similarity index 100% rename from kimaya_solutions/test_playground/assets/ml_regression.csv rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/ml_regression.csv diff --git a/kimaya_solutions/test_playground/assets/sales.csv b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/sales.csv similarity index 100% rename from kimaya_solutions/test_playground/assets/sales.csv rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/sales.csv diff --git a/kimaya_solutions/test_playground/assets/students.csv b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/students.csv similarity index 100% rename from kimaya_solutions/test_playground/assets/students.csv rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/students.csv diff --git a/kimaya_solutions/test_playground/assets/students_demo.csv b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/students_demo.csv similarity index 100% rename from kimaya_solutions/test_playground/assets/students_demo.csv rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/students_demo.csv diff --git a/kimaya_solutions/test_playground/assets/weather_timeseries.csv b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/weather_timeseries.csv similarity index 100% rename from kimaya_solutions/test_playground/assets/weather_timeseries.csv rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/assets/weather_timeseries.csv diff --git a/kimaya_solutions/test_playground/basics/boss.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/boss.py similarity index 100% rename from kimaya_solutions/test_playground/basics/boss.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/boss.py diff --git a/kimaya_solutions/test_playground/basics/conditionals.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/conditionals.py similarity index 100% rename from kimaya_solutions/test_playground/basics/conditionals.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/conditionals.py diff --git a/kimaya_solutions/test_playground/basics/hello.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/hello.py similarity index 100% rename from kimaya_solutions/test_playground/basics/hello.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/hello.py diff --git a/kimaya_solutions/test_playground/basics/input_output.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/input_output.py similarity index 100% rename from kimaya_solutions/test_playground/basics/input_output.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/input_output.py diff --git a/kimaya_solutions/test_playground/basics/loops.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/loops.py similarity index 100% rename from kimaya_solutions/test_playground/basics/loops.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/loops.py diff --git a/kimaya_solutions/test_playground/basics/vars_and_ops.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/vars_and_ops.py similarity index 100% rename from kimaya_solutions/test_playground/basics/vars_and_ops.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/basics/vars_and_ops.py diff --git a/kimaya_solutions/test_playground/intermediate/boss.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/boss.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/boss.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/boss.py diff --git a/kimaya_solutions/test_playground/intermediate/class_basics.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/class_basics.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/class_basics.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/class_basics.py diff --git a/kimaya_solutions/test_playground/intermediate/csv_handler.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/csv_handler.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/csv_handler.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/csv_handler.py diff --git a/kimaya_solutions/test_playground/intermediate/dict_ops.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/dict_ops.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/dict_ops.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/dict_ops.py diff --git a/kimaya_solutions/test_playground/intermediate/inheritance.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/inheritance.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/inheritance.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/inheritance.py diff --git a/kimaya_solutions/test_playground/intermediate/json_handler.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/json_handler.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/json_handler.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/json_handler.py diff --git a/kimaya_solutions/test_playground/intermediate/lambdas.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/lambdas.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/lambdas.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/lambdas.py diff --git a/kimaya_solutions/test_playground/intermediate/list_ops.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/list_ops.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/list_ops.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/list_ops.py diff --git a/kimaya_solutions/test_playground/intermediate/set_ops.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/set_ops.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/set_ops.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/set_ops.py diff --git a/kimaya_solutions/test_playground/intermediate/some_functions.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/some_functions.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/some_functions.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/some_functions.py diff --git a/kimaya_solutions/test_playground/intermediate/sql_handler.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/sql_handler.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/sql_handler.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/sql_handler.py diff --git a/kimaya_solutions/test_playground/intermediate/tuple_ops.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/tuple_ops.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/tuple_ops.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/tuple_ops.py diff --git a/kimaya_solutions/test_playground/intermediate/txt_handler.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/txt_handler.py similarity index 100% rename from kimaya_solutions/test_playground/intermediate/txt_handler.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/intermediate/txt_handler.py diff --git a/kimaya_solutions/test_playground/miscellaneous/basic_flask_routing.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/basic_flask_routing.py similarity index 100% rename from kimaya_solutions/test_playground/miscellaneous/basic_flask_routing.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/basic_flask_routing.py diff --git a/kimaya_solutions/test_playground/miscellaneous/ciphers.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/ciphers.py similarity index 100% rename from kimaya_solutions/test_playground/miscellaneous/ciphers.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/ciphers.py diff --git a/kimaya_solutions/test_playground/miscellaneous/os_path.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/os_path.py similarity index 100% rename from kimaya_solutions/test_playground/miscellaneous/os_path.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/os_path.py diff --git a/kimaya_solutions/test_playground/miscellaneous/some_algos.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/some_algos.py similarity index 100% rename from kimaya_solutions/test_playground/miscellaneous/some_algos.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/some_algos.py diff --git a/kimaya_solutions/test_playground/miscellaneous/some_cp_problems.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/some_cp_problems.py similarity index 100% rename from kimaya_solutions/test_playground/miscellaneous/some_cp_problems.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/some_cp_problems.py diff --git a/kimaya_solutions/test_playground/miscellaneous/some_data_structures.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/some_data_structures.py similarity index 100% rename from kimaya_solutions/test_playground/miscellaneous/some_data_structures.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/some_data_structures.py diff --git a/kimaya_solutions/test_playground/miscellaneous/terminal_chatbot.py b/SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/terminal_chatbot.py similarity index 100% rename from kimaya_solutions/test_playground/miscellaneous/terminal_chatbot.py rename to SOLUTIONS/kimayagaikwad2067-ship-it_solutions/test_playground/miscellaneous/terminal_chatbot.py