# Advanced data analysis: files, charts, and spreadsheets
Upload a messy sales CSV and ChatGPT will write and run real Python in a sandbox to clean it, chart it, and hand you back a polished file plus a publication-ready graph. This is Advanced Data Analysis (formerly Code Interpreter): a live Python environment attached to your chat. It is not the model guessing about your data from text. It is the model executing code against your actual file and reading the output.
This lesson takes one file from raw to finished, and shows you exactly how to pull the cleaned data and charts back out.
When you attach a file, ChatGPT can spin up a temporary Linux sandbox with Python, pandas, matplotlib, numpy, and friends preinstalled. It writes code, runs it, sees the errors or the results, and iterates, all without you touching a terminal.
Key properties to keep in mind:
pip install arbitrary packages or call APIs. It works with what is bundled and what you upload..csv, .xlsx, .json, .parquet, images, PDFs, and zipped archives. For spreadsheets, multiple sheets are accessible.Official overview: Advanced Data Analysis in the OpenAI Help Center.
Imagine q3_sales.csv exported from a CRMCRMCustomer Relationship Management: software and strategy to manage and analyse customer interactions throughout their lifecycle.View full definition →. It is realistically broken:
Revenue column like "$1,240.50" (string, with symbols and commas).OrderDate in mixed formats: 2025-07-03 and 07/14/2025.Region column with "north", "North ", and "NORTH".CustomerID values.You do not need to describe all of this up front. Let ChatGPT inspect it first.
Upload the file and start with a diagnostic prompt, not a cleanup command:
> Load this CSV. Show me row and column counts, dtypes, the count of nulls per column, the number of duplicate rows, and 5 sample rows. Do not change anything yet.
ChatGPT runs something close to this and reports back:
import pandas as pd
df = pd.read_csv("q3_sales.csv")
print(df.shape)
print(df.dtypes)
print(df.isna().sum())
print("duplicate rows:", df.duplicated().sum())
df.sample(5, random_state=0)Now you are arguing from facts. You can see that Revenue is an object (text), that CustomerID has 6 nulls, and that there are 14 duplicate rows. This profiling step is the single biggest quality lever. Skip it and you get plausible-looking code that silently mishandles your edge cases.
Give the cleanup as a numbered spec. Specificity here prevents the model from "helpfully" dropping rows you wanted to keep.
> Clean the data with these rules, and after each step print how many rows changed:
> 1. Strip $ and commas from Revenue, convert to float.
> 2. Parse OrderDate to datetime, coerce unparseable values to NaT and report how many.
> 3. Normalize Region to title case and trim whitespace.
> 4. Drop fully duplicate rows.
> 5. Leave rows with missing CustomerID in place, but add a boolean missing_customer flag.
> Save the result as q3_sales_clean.csv.
A senior data analyst would write essentially this:
import pandas as pd
df = pd.read_csv("q3_sales.csv")
before = len(df)
df["Revenue"] = (df["Revenue"].str.replace(r"[$,]", "", regex=True).astype(float))
df["OrderDate"] = pd.to_datetime(df["OrderDate"], format="mixed", errors="coerce")
unparsed = df["OrderDate"].isna().sum()
df["Region"] = df["Region"].str.strip().str.title()
df = df.drop_duplicates()
df["missing_customer"] = df["CustomerID"].isna()
df.to_csv("q3_sales_clean.csv", index=False)
print(f"rows: {before} -> {len(df)}, unparsed dates: {unparsed}")ChatGPT will show you the printed output ("rows: 1014 -> 1000, unparsed dates: 3") and give you a download link for q3_sales_clean.csv. Click it to save the cleaned file. That link points at the sandbox, so grab it before the session expires.
You can and should expand the code blocks ChatGPT runs. If it coerced 3 dates to NaT, ask which rows. The discipline that matters: treat the model like a fast junior analyst whose work you spot-check, not an oracle. When numbers feed a decision, ask it to print intermediate counts at every step (as we did above) so the transformation is auditable.
Now the fun part. Ask for analysis and a chart in one go:
> Using the cleaned data, give me monthly total revenue as a line chart. Label axes, add a title, format the y-axis as currency, and use a clean style. Then save it as a 300 DPI PNG I can download.
A clean version of what runs:
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
monthly = (df.set_index("OrderDate").resample("ME")["Revenue"].sum())
fig, ax = plt.subplots(figsize=(9, 5))
ax.plot(monthly.index, monthly.values, marker="o", linewidth=2)
ax.set_title("Q3 2025 Monthly Revenue")
ax.set_xlabel("Month")
ax.set_ylabel("Revenue")
ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x, _: f"${x:,.0f}"))
fig.tight_layout()
fig.savefig("monthly_revenue.png", dpi=300)You get the rendered chart inline plus a downloadable monthly_revenue.png. Iterate in plain language: "make it a bar chart," "add data labels on each point," "split by Region into small multiples." Each request re-runs the code against the same in-memory DataFrame, so you are not re-uploading anything.
One real constraint: matplotlib here renders text with the default font set, so emoji and some non-Latin scripts may not display. If a chart needs specific branding fonts, that is a job for your own tooling, not the sandbox.
Spreadsheet work is a strength. Ask for a pivot and a formatted Excel export:
> Build a pivot of total Revenue by Region (rows) and Month (columns). Write it to q3_summary.xlsx with the raw cleaned data on a second sheet named "data".
pivot = pd.pivot_table(df, values="Revenue", index="Region",
columns=df["OrderDate"].dt.strftime("%Y-%m"),
aggfunc="sum", fill_value=0)
with pd.ExcelWriter("q3_summary.xlsx") as writer:
pivot.to_excel(writer, sheet_name="summary")
df.to_excel(writer, sheet_name="data", index=False)The output is a real .xlsx with two sheets, ready to drop into a deck or email.
A one-off analysis is nice. The leverage comes from reuse.
If you do this weekly, your standards should not live in your memory. Put them where ChatGPT reads them every time. Inside a Project, set instructions like: "When I upload sales data, always profile first, always print row counts after each transform, format currency on charts, and export charts at 300 DPI." Files you add to a Project are scoped to it, so your sales work stays separate from everything else.
Wrap the whole workflow in a Custom GPT so colleagues get consistent output without writing prompts. Bake the profiling-first rule and your house chart style into its instructions. Advanced Data Analysis is a capability you toggle on for the GPT. Now a non-technical teammate uploads a CSV and gets your exact analysis pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.View full definition →.
For recurring reporting, scheduled tasks can prompt a chat on a cadence ("every Monday at 9am"). The catch: a scheduled task cannot reachreachThe number of unique people exposed to your message in a given period. Unlike impressions, reach counts each person once, no matter how often they see it.View full definition → into your laptop for a fresh file. Pair it with a Connector (to Google Drive, SharePoint, etc.) so the file source is reachable, or use the ChatGPT agent, which can browse and operate in its own virtual environment to fetch and process data. Match the tool to whether the data is already in the chat or has to be retrieved.
Knowledge check
1. What does ChatGPT's Advanced Data Analysis feature actually do when you upload a file?
2. Which statement about the Advanced Data Analysis sandbox is correct?
3. Advanced Data Analysis was previously known by what name in ChatGPT?
4. Select ALL correct answers about the limitations and behavior of the Advanced Data Analysis sandbox.
Sélectionnez toutes les réponses correctes.
5. Select ALL correct answers describing the realistic data problems in the example q3_sales.csv file.
Sélectionnez toutes les réponses correctes.
The chat sandbox is perfect for exploration and ad hoc reports. It is the wrong tool for a pipelinepipelineAll active sales opportunities across the stages of the sales process, together with their combined potential value and probability of closing.View full definition → that must run unattended, hit a database, and never hallucinate a column name. For that, move to the OpenAI API.
The same "model writes and runs Python" capability exists as the Code Interpreter tool in the Responses API. You attach a file, enable the tool, and the model executes code in a managed container, returning both the analysis and any generated file IDs you can download programmatically.
from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="gpt-5",
tools=[{"type": "code_interpreter", "container": {"type": "auto"}}],
input="Clean the attached sales CSV, then return total revenue by region as a table.",
)
print(resp.output_text)Use the APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.View full definition → path when you need scheduling on your own infrastructure, structured outputs you can validate, or integration into an existing app. Use the chat when a human is in the loop and you want to iterate visually. They share the same engine; the difference is control versus convenience.
If your output must slot into a downstream system, combine this with structured outputs so the summary returns as schemaschemaA schema is the formal blueprint that defines how data is structured, named, typed, and related within a database, file, or message.View full definition →-validated JSON rather than prose. That turns "nice analysis" into "data another program can trust."
.csv and .png outputs immediately. The sandbox is not storage.