To get started with artificial intelligence in Python, install a current Python, create a virtual environment, add scikit-learn and Jupyter, and build one small project end to end: load a dataset, split off a test set, train a model inside a pipeline and score it once on data it has never seen. PyTorch and hosted model APIs come after that.
This guide walks that path with code that runs as written: every sample was run with Python 3.14, scikit-learn 1.9.1 and PyTorch 2.14.0 in September 2026. You will train a classifier on a medical dataset that ships with scikit-learn, see how a mistake called data leakage makes a model look better than it is, rebuild the classifier as a small neural network, and call a hosted large language model without putting the API key in your code. It ends with the errors beginners hit most and what to learn next. If programming itself is new to you, our tips for new coders cover the path from a first language to a first code review.
Why Python is where most AI work starts
Python is not fast on its own, and for AI work it does not need to be. The arithmetic runs in compiled code underneath: NumPy, the array library that scikit-learn and pandas install as a dependency, describes its core as well-optimized C code. Python is the readable layer you write on top, which is why a few lines can load data, train a model and score it.
The other reason is the ecosystem. Data handling, classic machine learning, deep learning, notebooks and the SDKs for hosted models are all Python-first, and the numbers show it:
- In the Stack Overflow 2025 Developer Survey, 57.9% of respondents had done extensive development work in Python, up 7 percentage points from 2024. Among people learning to code, Python was the most used language, at 71.8%.
- GitHub's Octoverse 2025 found that TypeScript overtook Python as the most used language on GitHub in August 2025, but that Python remains dominant for AI and data science, with 2.6 million contributors, and powers nearly half of all new AI repositories.
In practice, most AI work you can do on a laptop is machine learning: instead of writing the rule yourself, you give the program labelled examples and it learns the rule. Your first project below is supervised classification, 30 measurements in and one of two labels out. These are the libraries it uses:
| Library | What it does in this guide | Install name |
|---|---|---|
| NumPy | Arrays and fast numerical math under the other libraries | numpy (installed automatically) |
| pandas | Tables of data: load, inspect, clean | pandas |
| scikit-learn | Classic machine learning: splitting, preprocessing, models, metrics | scikit-learn, imported as sklearn |
| PyTorch | Neural networks, with GPU support when you need it | torch |
| JupyterLab | Notebooks for exploring data and results | jupyterlab |
| Provider SDKs | Calling hosted language models | anthropic, openai, google-genai |
Choosing between competing frameworks is a separate question, covered in our AI frameworks comparison. For a first project, these defaults are enough, and the skills carry over to whichever tools you pick later.
Set up Python, a virtual environment and Jupyter
You need basic Python (variables, functions, imports), a terminal, and any recent Windows, macOS or Linux computer. You do not need a GPU: everything in this guide runs on a laptop CPU in seconds.
Choose the Python version
As of September 2026, use Python 3.14. The current release is 3.14.7, and the 3.14 series is supported until October 2030. Python 3.15 is planned for October 1, 2026, but wait before switching: PyTorch 2.14.0 publishes packages for Python 3.10 to 3.14 only, so on a 3.15 pre-release pip install torch stops with "No matching distribution found". scikit-learn 1.9 needs Python 3.11 or later, so anything from 3.11 to 3.14 runs this guide, and 3.14 is the sensible default.
Where to get it:
- Windows: install the Python install manager from python.org or the Microsoft Store, then run
py install 3.14. - macOS: the installer from python.org, Homebrew, or uv (below).
- Linux: your distribution's package, or uv.
Option 1: venv and pip, built into Python
On macOS or Linux:
mkdir ai-first-project
cd ai-first-project
python3.14 -m venv .venv
source .venv/bin/activate
python -m pip install scikit-learn pandas jupyterlab
jupyter lab
On Windows, in PowerShell:
mkdir ai-first-project
cd ai-first-project
py -3.14 -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install scikit-learn pandas jupyterlab
jupyter lab
A virtual environment is a folder, here .venv, with its own set of packages, isolated from the Python it was created from. Activating it puts its bin folder (Scripts on Windows) first on your PATH, so python and jupyter mean the project's copies. Treat it as disposable: it is not committed to Git and not copied between machines; you recreate it instead. Since Python 3.13, venv writes a .gitignore inside the folder so Git skips it automatically.
Installing into the system Python instead is not only untidy, it is often refused. On Homebrew's Python, and on Linux distributions that follow the same standard, pip stops with error: externally-managed-environment, because another package manager owns that installation. The packaging standard behind that error points users to virtual environments, which is the fix rather than a workaround.
Option 2: uv, one tool for Python versions, environments and lockfiles
uv init -p 3.14 ai-first-project
cd ai-first-project
uv add scikit-learn pandas jupyterlab
uv run jupyter lab
uv is a package and project manager from Astral, written in Rust, that replaces pip, virtualenv, pyenv and several other tools. It can install Python itself (uv python install 3.14). In a project, it creates the .venv folder and a uv.lock file the first time you add a package or run a project command, and uv run runs a command inside that environment without activating it.
| venv and pip | uv | |
|---|---|---|
| Comes with Python | Yes | No, one extra install |
| Installs Python versions | No | Yes |
| Records exact versions | Only if you run pip freeze by hand | Yes, in uv.lock |
| Good for | Following any tutorial as written | Projects you will keep and share |
Notebook or script
jupyter lab opens JupyterLab in your browser. A notebook is a file of code cells with the output of each shown below it, which makes it the natural place to explore data. Anything you will run again belongs in a script. JupyterLab installs with pip like any other package, and the one rule is that it must run your environment's Python: start it from the activated environment, or with uv run.
Build your first machine learning model with scikit-learn
The project: classify breast tumour samples as malignant or benign. The Breast Cancer Wisconsin (Diagnostic) dataset ships with scikit-learn, so there is nothing to download. It holds 569 samples, each with 30 measurements computed from a digitized image of a fine needle aspirate of a breast mass, labelled 212 malignant and 357 benign.
Note
This is a teaching dataset. scikit-learn's reference for load_breast_cancer describes it as a classic and very easy classification problem, and the dataset guide adds that these bundled datasets are often too small to represent real-world machine learning. The workflow transfers to real data; the score does not, and nothing here is a diagnostic tool.
Run each block below as a notebook cell, in order, or save them together as first_model.py and run python first_model.py.
Step 1: Load the data and look at it
from sklearn.datasets import load_breast_cancer
data = load_breast_cancer(as_frame=True)
X, y = data.data, data.target
print(X.shape)
print(data.target_names)
print(y.value_counts())
print(X[["mean area", "mean smoothness"]].agg(["min", "max"]))
(569, 30)
['malignant' 'benign']
target
1 357
0 212
Name: count, dtype: int64
mean area mean smoothness
min 143.5 0.05263
max 2501.0 0.16340
X is a pandas table of 569 rows and 30 columns; y holds the labels, where 0 means malignant and 1 means benign. Two things matter already. The classes are unbalanced (357 against 212), which will set the bar for a useful score. And the columns sit on very different scales: mean area runs from 143.5 to 2,501, mean smoothness from 0.05 to 0.16. The scikit-learn documentation on preprocessing warns that many of its models behave badly when features are not standardized, so scaling will be part of the model.
Step 2: Split before anything learns
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
print(X_train.shape, X_test.shape)
(455, 30) (114, 30)
test_size=0.2 holds back 20% of the rows, 114 of them, as the test set. stratify=y keeps the share of malignant and benign samples the same on both sides, and random_state=42 makes the split repeatable, so you get the numbers shown here. From this line on, the test rows are off limits until the last step. The scikit-learn guide to cross-validation calls training and testing on the same data a methodological mistake: a model that simply memorized the labels would score perfectly and predict nothing.

Step 3: Set a baseline
from sklearn.dummy import DummyClassifier
baseline = DummyClassifier(strategy="most_frequent")
baseline.fit(X_train, y_train)
print(f"Baseline accuracy: {baseline.score(X_test, y_test):.3f}")
Baseline accuracy: 0.632
A DummyClassifier ignores the measurements entirely. This one always answers "benign" and is right 63.2% of the time, 72 of 114. Every model you build has to beat that number, and it is a useful reminder that accuracy alone can flatter a model when one class is more common.
Step 4: Build a pipeline and cross-validate it
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
model = make_pipeline(StandardScaler(), LogisticRegression())
scores = cross_val_score(model, X_train, y_train, cv=5)
print(f"Cross-validation accuracy: {scores.mean():.3f} (+/- {scores.std():.3f})")
Cross-validation accuracy: 0.980 (+/- 0.013)
The pipeline chains two steps into one model: StandardScaler rescales each column to mean 0 and standard deviation 1, and LogisticRegression learns a weight for each column. Because they are fitted together, the scaler only ever learns its means and deviations from the rows the pipeline is trained on.
cross_val_score with cv=5 splits the training set into five folds, trains on four and scores on the fifth, five times over, and reports the scores. The average, 98.0% with little spread between folds, is your estimate of how the model will do on new data. Compare models and settings here, never on the test set.
Step 5: Train once and test once
from sklearn.metrics import classification_report, confusion_matrix
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred, target_names=data.target_names))
[[41 1]
[ 1 71]]
precision recall f1-score support
malignant 0.98 0.98 0.98 42
benign 0.99 0.99 0.99 72
accuracy 0.98 114
macro avg 0.98 0.98 0.98 114
weighted avg 0.98 0.98 0.98 114
In a scikit-learn confusion matrix, rows are the true classes and columns the predictions. Of 42 malignant test samples, 41 were caught and 1 was called benign; of 72 benign samples, 71 were right and 1 was flagged as malignant. Accuracy is 98%, against 63.2% for the baseline, and it agrees with the cross-validation estimate of 98.0%.
Accuracy hides which mistakes a model makes, so read the other columns too. Precision is the share of samples predicted malignant that really were; recall is the share of malignant samples the model found. Which one matters more depends on the use. In screening, a missed malignant sample is the expensive error, so you would watch malignant recall and accept more false alarms to raise it.
Data leakage: the mistake that makes models look better than they are
scikit-learn's page of common pitfalls defines data leakage as information that would not be available at prediction time being used to build the model. It produces optimistic scores in testing and poorer results on genuinely new data. A common cause is letting test rows into any step that learns from data, preprocessing included, and the rule that prevents it is short: never call fit on the test data.
The same page demonstrates how large the effect can be, using pure noise: 200 samples with 10,000 random features and random labels. Selecting the 25 "best" features on all the data before splitting produced 76% test accuracy on labels that cannot be predicted at all. Selecting them on the training rows only gave 50%, exactly what chance should give.
That is why the scaler in step 4 lives inside the pipeline. When cross_val_score trains on four folds, the pipeline refits the scaler on those four folds only, so the fold being scored never influences its own preprocessing. The same holds for every transformer you add later.
| Leak | Why it inflates the score | Fix |
|---|---|---|
| Scaling, filling gaps or selecting features on all rows before the split | Statistics from the test rows shape the training | Split first, and put every preprocessing step in a pipeline |
| Trying models and settings against the test set | The test set turns into training data by another name | Compare with cross-validation on the training set; test once |
| Rows from the same patient, customer or device on both sides | The model recognizes the individual, not the pattern | Split by group with GroupKFold |
| Shuffling data that is ordered in time | The model learns from the future to predict the past | Split with TimeSeriesSplit |
| A column recorded after the outcome | It encodes the answer | Drop anything that will not exist at prediction time |
Take a first step into deep learning with PyTorch
Deep learning uses neural networks: layers of learned weights joined by simple non-linear functions. They earn their complexity on images, audio, text and very large datasets. Building the same classifier as a small network is still the clearest way to see the moving parts. For the ideas behind the code, weights, backpropagation and the main architectures, see deep learning and NLP explained.
Install PyTorch into the same environment with python -m pip install torch, or uv add torch. Version 2.14.0, released on September 2, 2026, needs Python 3.10 or later. According to uv's PyTorch guide, the package on PyPI is built with CUDA for NVIDIA GPUs on Linux and is CPU-only on Windows; for a CPU-only Linux build or a CUDA build on Windows, copy the command from the selector on pytorch.org. This example runs on any CPU.
import torch
from torch import nn
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
# Learn the scaling from the training rows only, then apply it to both sets.
scaler = StandardScaler().fit(X_train)
X_train = torch.tensor(scaler.transform(X_train), dtype=torch.float32)
X_test = torch.tensor(scaler.transform(X_test), dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32).unsqueeze(1)
y_test = torch.tensor(y_test, dtype=torch.float32).unsqueeze(1)
torch.manual_seed(42)
model = nn.Sequential(
nn.Linear(30, 16), # 30 measurements in, 16 hidden units
nn.ReLU(),
nn.Linear(16, 1), # one score out: above 0 means "benign"
)
loss_fn = nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
for epoch in range(100):
model.train()
optimizer.zero_grad() # clear the previous gradients
loss = loss_fn(model(X_train), y_train) # forward pass and loss
loss.backward() # gradients for every weight
optimizer.step() # nudge the weights
if epoch % 25 == 0:
print(f"epoch {epoch:3d} loss {loss.item():.4f}")
model.eval()
with torch.no_grad():
predicted = (model(X_test) > 0).float()
accuracy = (predicted == y_test).float().mean().item()
print(f"Test accuracy: {accuracy:.3f}")
epoch 0 loss 0.7288
epoch 25 loss 0.0895
epoch 50 loss 0.0500
epoch 75 loss 0.0378
Test accuracy: 0.956
The split and the scaling are the same as before, done by hand this time, with the scaler fitted on the training rows only. The model has 513 parameters (weights and biases) in two linear layers with a ReLU between them. Each pass of the loop is one epoch over the training rows, and the PyTorch tutorial on optimization describes its three steps: optimizer.zero_grad() resets the gradients, which otherwise add up from one pass to the next; loss.backward() computes how the loss changes with every weight; and optimizer.step() adjusts each weight using those gradients. The loss function, BCEWithLogitsLoss, measures how far the raw scores are from the 0 and 1 labels.

The result is the lesson. The training loss fell from 0.73 to below 0.04 by epoch 75, yet the network scored 95.6% on the test set, below the 98% of the two-step logistic regression. On a few hundred rows of clean numbers, more capacity is not what the problem needs. Keep the simplest model that works as your baseline, and reach for neural networks when the data is images, sound or text, or when there is far more of it.
Two notes for later. On a machine with a supported GPU, the PyTorch tutorials select it with torch.accelerator (CUDA, MPS and others) and move the model and data to it. And if you prefer a higher-level API, Keras 3 builds the same kind of model on a backend you choose: JAX, TensorFlow or PyTorch.
Call a hosted language model from Python without leaking your key
Much of what people now mean by AI is a large language model that you call over an API rather than train. Each provider publishes a Python SDK, and each reads its key from an environment variable by default: ANTHROPIC_API_KEY for Anthropic's anthropic package, OPENAI_API_KEY for OpenAI's openai package, and GEMINI_API_KEY or GOOGLE_API_KEY for Google's google-genai package, which calls models such as Gemini. The example uses Anthropic's SDK; the pattern is the same with the others.
- Create an API key in the provider's console, and set a monthly spend limit before you write any code. On Anthropic's console, spend limits sit under Settings, then Billing.
- Put the key in the environment of the terminal that will run Python. On macOS or Linux,
export ANTHROPIC_API_KEY="paste-your-key-here". In PowerShell,$Env:ANTHROPIC_API_KEY = "paste-your-key-here", which lasts for the current session only. - Install the SDK into your environment:
python -m pip install anthropic. Anthropic's Python SDK needs Python 3.10 or later. - Run the script below as
ask_model.py.
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from the environment
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "In two sentences, what is data leakage in machine learning?",
}
],
)
for block in response.content:
if block.type == "text":
print(block.text)
print(f"Stop reason: {response.stop_reason}")
print(f"Tokens: {response.usage.input_tokens} in, {response.usage.output_tokens} out")
The client finds the key itself, as Anthropic's getting started guide describes, so the key never appears in the file. claude-opus-5-5 is the model Anthropic's models overview suggests starting with as of September 2026, priced at $4 per million input tokens and $20 per million output tokens. max_tokens is the most tokens the model may generate before it stops, which caps the length and cost of the reply. The response is a list of content blocks, so the loop prints only the text ones, and usage reports the tokens you are billed for. The SDK retries connection errors, rate limits (HTTP 429) and server errors twice by default before raising an exception.
Typing the key into every new terminal gets old quickly. The usual alternative is a .env file read by python-dotenv, which Anthropic's SDK documentation also suggests. Install it with python -m pip install python-dotenv, put one line in .env in the project folder (ANTHROPIC_API_KEY=paste-your-key-here), add .env to .gitignore, and call load_dotenv() before creating the client:
from dotenv import load_dotenv
load_dotenv() # copies ANTHROPIC_API_KEY from .env into the environment
Before your first commit, git check-ignore -v .env should print the .gitignore rule that excludes the file. If it prints nothing, the file is not ignored, and the next git add will pick up the key.

Warning
Never paste an API key into a notebook cell. Notebooks save their code and output inside the .ipynb file, and that file is what gets committed, emailed and shared. If a key does leak, the OWASP Secrets Management Cheat Sheet says to revoke it immediately, issue a new one and remove the old one wherever it was exposed.
Environment variables are the right tool on your own computer. On servers, OWASP notes that they are readable by other processes and can end up in logs, so production systems load keys from a secrets manager instead. The same rules apply to every credential in your code; our guide to secure coding best practices covers the rest. Finally, treat each prompt as data leaving your machine: do not send personal or confidential information until you know what the provider does with it and what your organization allows.
Common errors when getting started, and how to fix them
| Symptom | Likely cause | Fix |
|---|---|---|
error: externally-managed-environment from pip | You are installing into a Python that the operating system or Homebrew manages | Create and activate a virtual environment, then install |
ModuleNotFoundError: No module named 'sklearn' right after installing | The terminal or notebook is running a different Python | Activate .venv (or use uv run) and start Jupyter from there |
pip install sklearn fails | sklearn on PyPI is a deprecated placeholder | Install scikit-learn, then import it as sklearn |
No matching distribution found for torch | Your Python is newer than PyTorch's packages (a 3.15 pre-release, as of September 2026) | Use Python 3.14 |
PowerShell refuses to run Activate.ps1 | The script execution policy blocks it | Run Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser once |
Could not resolve authentication method from the SDK | ANTHROPIC_API_KEY is not set in the terminal that runs Python | Set it in that terminal, or call load_dotenv() before creating the client |
| Scores that look too good in testing, then fall apart on new data | Leakage, or a test set that has been used for tuning | Put every preprocessing step in a pipeline and score a fresh test set once |
The PowerShell fix is the one the venv documentation gives; it applies to your user account only.
What to learn next
You now have the loop every machine learning project follows: set up, look, split, baseline, train with cross-validation, test once. The next steps build on it in roughly this order:
- Your own data. Load a CSV with pandas and check it before training: missing values, duplicate rows, and columns recorded after the outcome you want to predict.
- More of scikit-learn. Try tree ensembles such as
HistGradientBoostingClassifieron tabular data, search settings withGridSearchCVinside cross-validation, and choose metrics that match the cost of each error. The scikit-learn Getting Started page leads into the user guide. - PyTorch properly. The Learn the Basics tutorials cover tensors, datasets and data loaders, automatic differentiation, training and saving models, on image data where neural networks earn their keep.
- Building with hosted models. Ask for structured output instead of free text, ground answers in your own documents, and keep a set of real test questions that every prompt or model change must pass before it ships.
- The math, as you need it. Linear algebra explains what a layer computes, probability what a score means, and derivatives how training moves the weights.
When a notebook result needs to become something a team relies on, most of the work moves from the model to everything around it. Our AI and automation service uses a language model only where a step needs judgment, tests every model or prompt change against an evaluation set built from your real cases, and removes personal data before the model reads it. Custom software development covers the platform, APIs and back end that the model plugs into.


