Imagine uploading a CSV file, asking a question in plain English, and instantly receiving a chart, statistical summary, and explanation of your data. This is the concept behind an AI data analyst built with Python. By integrating a language model with data analysis tools, you can interpret questions, calculate results, identify patterns, and communicate findings without writing each Pandas query manually.
In this tutorial, we’ll build a local application using Pandas, Streamlit, Plotly, and Ollama. All tools are free and open source; no paid API or subscription is required.
AI Data Analyst That Turns CSV Files into Insights
The application allows users to upload a CSV file and ask questions such as:
- Which product category generated the highest revenue?
- How have monthly sales changed?
- Are there unusual values in this dataset?
- Which categories have the highest average order value?
Pandas performs calculations, Plotly generates interactive charts, Streamlit provides the interface, and a local LLM translates questions into analysis instructions and summarizes results.
Step 1: Install the free tools
Install the required Python packages and Ollama, which runs compatible open-source language models locally:
pip install streamlit pandas plotly ollama
ollama pull llama3.2
Create a file named app.py. The application uses Streamlit’s CSV uploader and Plotly’s interactive charts.
Step 2: Let the LLM interpret questions safely
Instead of asking the LLM to generate and execute arbitrary Python code, we’ll have it return a structured analysis plan. The application will validate this plan and execute only predefined Pandas operations.
This is an important engineering decision. Generated code can be incorrect or unsafe, especially if it accesses files or runs system commands:
import json
import pandas as pd
import plotly.express as px
import streamlit as st
from ollama import chat
MODEL = "llama3.2"
def create_plan(question, df):
prompt = f"""
Return JSON only with these fields:
operation, group_column, value_column.
Allowed operations:
summary, groupby_sum, groupby_mean, trend, anomalies.
Use null for unused columns.
Choose only columns from this list:
{df.columns.tolist()}
Question: {question}
"""
response = chat(
model=MODEL,
messages=[{"role": "user", "content": prompt}],
format={
"type": "object",
"properties": {
"operation": {
"type": "string",
"enum": [
"summary", "groupby_sum",
"groupby_mean", "trend", "anomalies"
]
},
"group_column": {
"type": ["string", "null"]
},
"value_column": {
"type": ["string", "null"]
}
},
"required": [
"operation", "group_column", "value_column"
]
}
)
return json.loads(response.message.content)This function translates natural-language questions into a limited set of operations. While structured output constrains the format, you must still validate returned values and column types before use.
Step 3: Execute the analysis with Pandas
Next, create a function to perform the calculations. The LLM selects the operation, but Pandas determines the actual results:
def analyze(df, plan):
operation = plan["operation"]
group_col = plan["group_column"]
value_col = plan["value_column"]
if operation == "summary":
return df.describe(include="all").fillna("").to_string(), None
if group_col not in df.columns or value_col not in df.columns:
raise ValueError("Invalid column selected.")
if operation in ("groupby_sum", "groupby_mean"):
if not pd.api.types.is_numeric_dtype(df[value_col]):
raise ValueError("Value column must be numeric.")
grouped = df.groupby(group_col)[value_col]
result = (
grouped.sum() if operation == "groupby_sum"
else grouped.mean()
).sort_values(ascending=False).head(20)
return result.to_string(), px.bar(
result, title=f"{operation}: {value_col}"
)
if operation == "trend":
dates = pd.to_datetime(df[group_col], errors="coerce")
values = pd.to_numeric(df[value_col], errors="coerce")
result = pd.DataFrame({
"date": dates, "value": values
}).dropna().sort_values("date")
if result.empty:
raise ValueError("No valid dates or numeric values.")
return result.head(1000).to_string(index=False), px.line(
result, x="date", y="value", title="Trend over time"
)
if operation == "anomalies":
values = pd.to_numeric(df[value_col], errors="coerce")
mean, std = values.mean(), values.std()
if pd.isna(std) or std == 0:
return "No variation to evaluate.", None
unusual = df[(values - mean).abs() > 3 * std]
return unusual.head(100).to_string(index=False), None
raise ValueError("Unsupported operation.")The anomaly detector uses a simple three-standard-deviation rule. This serves as a useful baseline for approximately normal numerical data, but it is not a universal definition of an anomaly.
Preparing for Your AI/ML Interview?
Projects like this help you develop practical skills, but it is also important to explain your technical decisions clearly in interviews. My book, Cracking Your First AI/ML Interview, can help you prepare for that next step.
Step 4: Build the interactive dashboard
Add the following code at the bottom of app.py. Users can upload a CSV, ask a question, review the result, and view a chart if the selected operation supports it:
st.title("AI Data Analyst")
st.write("Upload a CSV and explore your data using natural language.")
uploaded = st.file_uploader("Upload your CSV file", type=["csv"])
if uploaded:
try:
df = pd.read_csv(uploaded)
if df.empty or len(df.columns) == 0:
st.error("The CSV contains no usable data.")
st.stop()
st.subheader("Dataset preview")
st.dataframe(df.head(10))
st.write(f"{len(df):,} rows · {len(df.columns)} columns")
question = st.text_input(
"Ask a question",
placeholder="Which category has the highest sales?"
)
if st.button("Analyze") and question:
with st.spinner("Analyzing your data..."):
plan = create_plan(question, df)
result, chart = analyze(df, plan)
st.subheader("Analysis results")
st.code(result)
if chart is not None:
st.plotly_chart(chart, use_container_width=True)
with st.spinner("Summarizing findings..."):
response = chat(
model=MODEL,
messages=[{
"role": "user",
"content": (
"Summarize these computed results accurately. "
"Do not invent facts or causal explanations.\n"
+ result[:6000]
)
}]
)
st.subheader("What the data suggests")
st.write(response.message.content)
except Exception as exc:
st.error(f"Could not analyze the file: {exc}")Run the application:
streamlit run app.py



Keep Ollama running locally. You can now upload a CSV and ask questions about category comparisons, numerical summaries, trends, and unusual values.
The Takeaway
Building an AI data analyst is a practical way to integrate Python, Pandas, LLMs, and visualization in a single application.
The most important design choice is to let the LLM interpret the question while trusted Python code performs the calculations. This approach makes results easier to validate and the application easier to debug.
Start with a few supported operations, test them against known answers, and expand only when you can verify the results. An effective AI data analyst not only explains data but also performs analysis accurately and presents findings clearly.
Thank you for reading this article on building an AI data analyst in Python that turns CSV files into insights. For more insights on AI and machine learning, please follow me on Instagram.





