3c.8 PAL Model integration
See the working text for this QS in
- #619_.docx.
- Demo URL there are actually many … this was a chaotic demo.
AIP/FDE-led parts in demo 8
2c.2: pipeline + AI model » results
AIP:
Palantir was built around the idea of finding meaningful signals in massive, noisy datasets — and what you are describing maps directly onto that core mission. Here is how your demo could evolve into that pattern using Foundry’s tools:
- Batch Inference — Find Anomalies at Scale. Run your model across an entire dataset on a schedule. Records where the model’s prediction diverges significantly from the actual value become your flagged anomalies — the needles in the haystack.
- Tools: Python Transforms or Pipeline Builder for the inference pipeline, writing flagged records back to a Foundry dataset.
ME:
In this first test, the test inference data was run through the pipeline/model. And results were as expected.

2c.3-5: deploy model / function / UI app (individual input / results)
I spent several weeks doing PAL demos (on a trial account that PAl so graciously offers) to get a grounded understanding of what PAL does (of course, PAL does much more, but this to me is the core ability, where it all started, the haystack needle search algorithm). After a little over 2 weeks I finally got the gist. I suggested to PAL AI that we create a demo that I thought would reveal the gist of the needle in the haystack search (this demo was my original idea). The built-in PAL AI (AIP) chatbot agreed “whole-heartedly”. AIP and I were able to create a demo that showed by example the core of how PAL does the needle search.
(1) In Your Housing Demo — What Anomalies Could You Detect?
Your model predicts house prices based on features like square footage, location, etc. Anomalies would be records where the actual value diverges sharply from the predicted value, which could indicate:
- A property sold far below market value (distressed sale, fraud, money laundering)
- A property sold far above market value (inflated appraisal, market manipulation)
- Unusual feature combinations (e.g. tiny square footage but extremely high price — could indicate a data error or something more interesting)

Left: A training data point; right: An inference test point similar to that training point (if the result is not ~=162178.45 then we found a needle in a haystack) 
2c.X: REAL WORLD detect from big data input (streaming??)
AIP:
So the progression from your demo is clean: same model, same tools, just pointed at a larger dataset with a pipeline that runs continuously or on schedule — and suddenly you have a genuine threat-detection or anomaly-detection system, which is exactly what Palantir was originally designed to power.
Streaming — Real-Time Detection.
- For truly real-time detection, Foundry supports streaming pipelines that process records as they arrive with very low latency — on average under 15 seconds from ingestion to availability in the Ontology.
- This means your model could score incoming records in near real-time as events happen.
- The key trade-off is cost and complexity — streaming compute runs continuously, whereas batch runs on a schedule. For use cases that can tolerate more than 10 minutes of latency, batch is simpler and cheaper.
Surfacing the Results Once anomalies are flagged, the Foundry stack lets you operationalize them:
- Ontology — flagged records become Objects with properties like anomaly_score or risk_level
- Workshop — analysts see a live operational UI showing flagged cases
- Foundry Rules — trigger automated alerts when thresholds are breached
- Actions — analysts can act directly on flagged objects (escalate, dismiss, investigate)
(2) & (3) Real-World Examples
This is where Palantir’s original mission becomes clear. The pattern is always the same: model what “normal” looks like, then flag deviations at scale.
- Counter-terrorism (your 9/11 example) – Exactly right. A model trained on normal flight school enrollment patterns could flag clusters of foreign nationals enrolling simultaneously in heavy aircraft training with no commercial aviation career profile. The signal existed — the challenge was connecting it across siloed datasets.
- Military / Geospatial Intelligence – Tracking movement patterns of known military or government figures. If leaders of a rogue state all simultaneously move to hardened bunkers, go radio-silent, or alter convoy patterns — that behavioral deviation from baseline is the signal. Palantir’s Gotham product was built precisely for this kind of pattern-of-life analysis.
- Financial Crime – A model trained on normal transaction behavior flags
accounts with sudden spikes in cross-border transfers, structuring behavior (many transactions just below reporting thresholds), or connections to flagged counterparties. - Pandemic / Biosurveillance – Unusual spikes in hospital admissions, pharmacy purchases of specific drugs, or search query patterns in a geographic cluster — all deviating from seasonal baseline models — can indicate an emerging outbreak before it is officially reported.
- Supply Chain / Critical Infrastructure – Unusual procurement patterns
a state actor quietly buying large quantities of specific industrial components that have dual military use — flagged against a baseline of normal trade flows.
The common thread across all of these is exactly what you described:
a very large, noisy dataset, a model of what normal looks like, and a pipeline that continuously scores incoming data and surfaces the deviations for human analysts to act on. That is the Palantir loop — ingest, model, detect, operationalize, act.
NOTES
ME: 01 at the URL is the following tutorial text
"Action: Download data
the labeled American Housing data source and upload it in the data folder as housing_features_and_labels. Download the unlabeled American Census data source and upload it to the data folder as housing_inference_data. You can upload a CSV file into Foundry by dragging it into the folder structure - for this tutorial, upload it as a structured dataset."
below are the 2 files
- file name
- columns
- sample data
i cant make sense of the data... can you?
housing_features_and_labels.csv
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value id
-118.49 34.2 35 1109 206 515 202 5.2118 215800 8500
-118.49 34.19 23 2087 571 1809 553 3.1667 202000 8501
-118.49 34.18 31 3073 674 1486 684 4.8984 311700 8502
-118.49 34.16 37 3333 488 1171 485 6.4958 500001 8503
housing_inference_data.csv columns and rows
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income
-117.1168977 34.684977139164296 33.41529033324941 1107.0950571425185 206.14122690195296 515.3616070616154 200.96441266513685 4.744947497396011
-118.7941044 35.61620336 22.38140796823065 2087.2893080486674 572.6807934576076 1808.8155056894122 553.1940466869836 4.159838759559566
-118.0265845 33.75109689167518 31.62426649663079 3073.2576680241095 674.6271680285655 1483.7335280756172 685.3894404 5.456310913332794
..............................
FDE: Yes. The data makes sense once you separate features from label/target.
This is a simple supervised machine learning setup.
What the tutorial is doing
It wants to train a model that predicts:
median_house_value
from census/housing features such as:
longitude
latitude
housing_median_age
total_rooms
population
median_income
So the model learns:
housing features → predicted house value
File 1: housing_features_and_labels.csv
This is the training dataset.
It has both:
Input features
These are the columns the model uses to make a prediction:
longitude
latitude
housing_median_age
total_rooms
total_bedrooms
population
households
median_income
Label / target
This is the value the model is trying to learn to predict:
median_house_value
ID column
This is just an identifier:
id
So one row means:
For a census area at this longitude/latitude, with this number of rooms, bedrooms, people, households, and median income, the known median house value was X.
Example:
| longitude | latitude | median_income | median_house_value |
|---|---|---|---|
| -118.49 | 34.2 | 5.2118 | 215800 |
Meaning:
This area had median income
5.2118, and the known median house value was$215,800.
File 2: housing_inference_data.csv
This is the inference / prediction dataset.
It has only the input features:
longitude
latitude
housing_median_age
total_rooms
total_bedrooms
population
households
median_income
It does not have:
median_house_value
Because that is what the model is supposed to predict.
So one row means:
Here is a census area with known features, but unknown house value. Use the trained model to estimate the median house value.
Why there are two files
Training file:
features + known label
Used to train/test model
Inference file:
features only
Used to generate predictions
Diagram:
flowchart LR
A["housing_features_and_labels.csv<br/><br/>Features + known median_house_value"] --> B["Train model<br/><br/>Learn relationship between features and value"]
B --> C["Trained regression model"]
D["housing_inference_data.csv<br/><br/>Features only<br/>No median_house_value"] --> C
C --> E["Predictions<br/><br/>estimated median_house_value"]
What each column means
| Column | Meaning |
|---|---|
longitude |
Geographic longitude of the census area |
latitude |
Geographic latitude of the census area |
housing_median_age |
Median age of houses in the area |
total_rooms |
Total rooms in the area/block group |
total_bedrooms |
Total bedrooms in the area/block group |
population |
Population in the area |
households |
Number of households in the area |
median_income |
Median income in the area, usually scaled |
median_house_value |
Target label: actual median home value |
id |
Row identifier |
Important simplification
This is not individual houses.
It is more like:
one row = one geographic census district / block group
The model is not predicting the price of a specific house. It is predicting:
median house value for an area
In one sentence
The first file trains a regression model using census-area features and known house values; the second file contains new census-area features where the house value is unknown and should be predicted by the trained model.
ME: 02 thats great info… but what i really cant understand is what the numbers represent. the units.
Good question — the column names are misleading unless you know the original dataset.
This is based on the California Housing dataset from the 1990 U.S. Census. Each row is a census block group, not one house.
Units / meaning of the numbers
| Column | What the number represents | Unit / scale |
|---|---|---|
longitude |
Geographic longitude | Decimal degrees |
latitude |
Geographic latitude | Decimal degrees |
housing_median_age |
Median age of houses in that block group | Years |
total_rooms |
Total number of rooms across all households in the block group | Count of rooms |
total_bedrooms |
Total number of bedrooms across all households in the block group | Count of bedrooms |
population |
Number of people living in the block group | Count of people |
households |
Number of households in the block group | Count of households |
median_income |
Median household income in the block group | Tens of thousands of USD, approximately |
median_house_value |
Median house value in the block group | USD |
id |
Row identifier | No real-world unit |
Example row
longitude: -118.49
latitude: 34.20
housing_median_age: 35
total_rooms: 1109
total_bedrooms: 206
population: 515
households: 202
median_income: 5.2118
median_house_value: 215800
id: 8500
Means:
Census block group
8500is located around longitude-118.49, latitude34.20.
The median housing age is about 35 years.
Across the whole block group, there are 1,109 rooms, 206 bedrooms, 515 people, and 202 households.
Median income is about 5.2118 × $10,000 = $52,118.
Median house value is $215,800.
Important: not individual homes
This row does not mean:
one house has 1109 rooms
It means:
the whole census block group has 1109 total rooms
So the row is an area summary.
Why inference data has decimals
Your inference file has values like:
housing_median_age = 33.415
total_rooms = 1107.095
population = 515.36
Those are strange because counts normally should be whole numbers.
That likely means the inference data was synthetically generated or perturbed from original census rows. For modeling, decimals are acceptable because the model treats them as numeric features, but real census counts would usually be integers.
One-line interpretation
Each row describes one geographic census block group using location, housing totals, population, household count, income, and known/predicted median house value.
FDE: Yes. That output means the dataset object was created/written, but Jupyter is just showing the Python object reference:
<foundry.transforms._dataset.Dataset at ...>
To view the data, do one of these.
Option 1: Read it back in the notebook
Run:
housing_test_data.read_table(format="pandas").head()
or:
test_saved = housing_test_data.read_table(format="pandas")
test_saved
Option 2: Open it in Foundry
In the left Data panel, click:
housing_test_data
or click the ... menu next to it and choose something like:
Open
Open in dataset preview
Option 3: Check row count
Run:
housing_test_data.read_table(format="pandas").shape
You should see something like:
(number_of_rows, number_of_columns)
Why you saw that object text
This line:
housing_test_data = Dataset.get("housing_test_data")
returns a dataset handle, not the table contents.
To see contents, use:
.read_table(format="pandas")
Yes — this cell was successful.
Evidence:
- No error traceback appeared.
- The model pipeline was displayed.
- The final object shows:
Pipeline
├─ SimpleImputer
├─ StandardScaler
└─ LinearRegression
That means this ran successfully:
model.fit(X_train, y_train)
So your linear regression model has been trained.
Small note: the step name says "classifier", but the model is actually:
LinearRegression()
So it is a regression model, not a classifier. The name is harmless, but cleaner would be:
("regressor", LinearRegression())
But yes — training succeeded.

2b.6 ME: how can i test this model? using pipeline, or just some simple verification test
You can test it simply in the notebook first. That is the easiest verification.
Simple notebook test
Run this in a new cell:
X_test = test_df[numeric_features]
y_test = test_df["median_house_value"]
predictions = model.predict(X_test)
predictions[:10]
That should show the first 10 predicted house values.
Compare predictions to actual values
Run:
import pandas as pd
results = test_df.copy()
results["predicted_median_house_value"] = predictions
results["error"] = results["predicted_median_house_value"] - results["median_house_value"]
results[
[
"median_income",
"housing_median_age",
"total_rooms",
"median_house_value",
"predicted_median_house_value",
"error",
]
].head(10)
This gives you a simple visual check:
actual value vs predicted value
Calculate basic error metric
Run:
from sklearn.metrics import mean_absolute_error, r2_score
mae = mean_absolute_error(y_test, predictions)
r2 = r2_score(y_test, predictions)
mae, r2
Interpretation:
- MAE = average prediction error in dollars.
- R² = how much variation the model explains.
- closer to
1.0is better, - around
0means weak, - negative means bad.
- closer to
Quick single-row test
sample = X_test.head(1)
model.predict(sample)
Do you need a pipeline?
Not yet.
Use:
Notebook test first
Then later:
batch inference pipeline
if you want to apply the model to a full dataset and write predictions to Foundry.
Minimal verification
Run this:
X_test = test_df[numeric_features]
y_test = test_df["median_house_value"]
predictions = model.predict(X_test)
from sklearn.metrics import mean_absolute_error, r2_score
print("MAE:", mean_absolute_error(y_test, predictions))
print("R2:", r2_score(y_test, predictions))
print(predictions[:10])
2b.7 ME: pipeline test step by step
The simplest pipeline test is:
housing_test_data → apply model → housing_test_predictions
You are testing whether the published model can take a Foundry dataset as input and produce predictions as a new dataset.
Step 0 — Know what you already have
You already have:
Input dataset
housing_test_data
This has actual known values, including:
median_house_value
Published model
linear_regression_model
Your model expects these input columns:
median_income
housing_median_age
total_rooms
Step-by-step pipeline test
1. Create a new Pipeline Builder pipeline
Go to your project/folder and create a new pipeline.
Name it something simple:
test_model_pipeline
or:
housing_model_inference_test
2. Add input dataset
Add dataset:
housing_test_data
This is the dataset you saved from test_df.
3. Add model inference transform
Add a transform/node. Search for one of these terms:
model
predict
inference
apply model
batch inference
You are looking for something like:
Apply model
Run model
Model inference
Batch inference
Predict with model
The exact UI name may differ.
4. Select the model
In the model inference transform, select:
linear_regression_model
If it asks for a version, choose the published version you just created.
5. Map input columns
The model only needs these columns:
median_income
housing_median_age
total_rooms
Map them like this:
| Model input | Dataset column |
|---|---|
median_income |
median_income |
housing_median_age |
housing_median_age |
total_rooms |
total_rooms |
Do not feed median_house_value into the model. That is the actual answer used for comparison.
6. Configure output prediction column
If the transform asks for an output column name, use:
predicted_median_house_value
If Foundry auto-generates a name like:
prediction
that is also fine.
7. Keep useful columns
In the output, keep at least:
median_income
housing_median_age
total_rooms
median_house_value
predicted_median_house_value
The key is to keep both:
actual value = median_house_value
predicted value = predicted_median_house_value
8. Add output dataset
Create/write the result to a new dataset:
housing_test_predictions
So the flow becomes:
housing_test_data
↓
model inference using linear_regression_model
↓
housing_test_predictions
9. Preview
Preview the output.
Check:
- It has rows.
- It has the original columns.
- It has a prediction column.
- Row count should match
housing_test_data.
Expected:
housing_test_data rows = housing_test_predictions rows
10. Optional: add error column
If Pipeline Builder lets you add a calculated column, create:
prediction_error = predicted_median_house_value - median_house_value
This helps compare prediction vs actual.
Final expected output
Your final dataset should look conceptually like:
| median_income | housing_median_age | total_rooms | median_house_value | predicted_median_house_value | prediction_error |
|---|---|---|---|---|---|
| 4.8984 | 31 | 3073 | 311700 | 256476 | -55224 |
| 6.4958 | 37 | 3333 | 500001 | 337128 | -162873 |
Simplest diagram
flowchart LR
A["housing_test_data<br/>test rows with actual values"] --> B["Apply model<br/>linear_regression_model"]
B --> C["housing_test_predictions<br/>actual + predicted values"]
If you cannot find “Apply model”
If Pipeline Builder does not show any model/prediction/inference transform, then the simplest test is not through Pipeline Builder. The fallback is a tiny Python transform/notebook step.
But first try searching Pipeline Builder for:
model
inference
predict
is this the result?
Yes — this is the result.
You created the output dataset:
housing_test_predictions
It has:
3.4K rows
4 columns
And the columns are:
median_income
housing_median_age
total_rooms
prediction
So the pipeline successfully did:
housing_test_data
↓
linear_regression_model
↓
housing_test_predictions
The left panel confirms the inputs:
housing_test_datalinear_regression_model
And it says it was updated via:
housing_model_inference_test
So yes: this is your batch inference output.
One note: this output only has the model input columns plus prediction. If you want to compare prediction to actual value, include median_house_value in the pipeline output too.


yes, need to add a few columns maybe. but now, is it possible to take the current result and add it to a UI app where I can entere the data and the result computed?
Yes — absolutely possible.
But it is a different pattern from the pipeline test.
What you have now: batch inference
Current flow:
dataset rows → model → prediction dataset
This is good for predicting many rows at once.
What you want next: interactive inference app
Desired flow:
user enters values in UI
↓
model runs once
↓
prediction shown on screen
Example user inputs:
median_income = 5.2
housing_median_age = 30
total_rooms = 3000
Output:
predicted median house value = 256,000
Simplest Palantir architecture
Workshop app
↓
Input widgets / variables
↓
Function or published model function
↓
Live model deployment
↓
Display prediction
Steps at high level
1. Deploy the model
You need a live model deployment, like the one you created earlier.
The model must be able to accept:
median_income
housing_median_age
total_rooms
and return:
prediction
2. Publish the model as a Function
On the model deployment page, there is usually a section like:
Publish Function
This creates a callable function around the model.
That function is what Workshop can use.
3. Create a Workshop app
Create a small Workshop app with three inputs:
median_income
housing_median_age
total_rooms
Use number input widgets.
4. Add a function-backed value
Configure a Workshop variable or output value that calls the model function.
Pass the three input values into the function.
5. Display the result
Add a text/card widget showing:
Predicted median house value: $X
Concept diagram
flowchart LR
A["Workshop UI<br/>User enters 3 values"] --> B["Function call<br/>predict_house_value"]
B --> C["Live model deployment<br/>linear_regression_model"]
C --> D["Prediction shown in app"]
Important distinction
| Use case | Tool |
|---|---|
| Predict many rows and save dataset | Pipeline Builder batch inference |
| Let user enter values and get one prediction | Workshop + Function + live model |
| Compare predictions to actual values | Dataset / pipeline / notebook |
| Operational app for users | Workshop |
So yes: your next logical demo can be:
Build a tiny Workshop app that lets me type three numbers and returns a model prediction.
NOTES
X The gist of PAL AI haystack needle detection (per demo D8)
ME:
- (1) so in our specific example, we could detect what kinds of abnormalities?
- (2) but in real examples, what might the dataset and modell be about? for example, for 9/11, if there had been a palantir app running looking for unusual numbers of foreign residents wanting to train to fly large airliners. or
- (3) in current wars, if tracked leaders of a rogue state all start doing soemthing unusall at one time… can you give some examples?
AIP (PAL built-in AI):
Great framing — let me take each part in turn.
(1) In Your Housing Demo — What Anomalies Could You Detect?
Your model predicts house prices based on features like square footage, location, etc. Anomalies would be records where the actual value diverges sharply from the predicted value, which could indicate:
- A property sold far below market value (distressed sale, fraud, money laundering)
- A property sold far above market value (inflated appraisal, market manipulation)
- Unusual feature combinations (e.g. tiny square footage but extremely high price — could indicate a data error or something more interesting)

Left: A training data point; right: An inference test point similar to that training point (if the result is not ~=162178.45 then we found a needle in a haystack) 
(2) & (3) Real-World Examples
This is where Palantir’s original mission becomes clear. The pattern is always the same: model what “normal” looks like, then flag deviations at scale.
- Counter-terrorism (your 9/11 example) – Exactly right. A model trained on normal flight school enrollment patterns could flag clusters of foreign nationals enrolling simultaneously in heavy aircraft training with no commercial aviation career profile. The signal existed — the challenge was connecting it across siloed datasets.
- Military / Geospatial Intelligence – Tracking movement patterns of known military or government figures. If leaders of a rogue state all simultaneously move to hardened bunkers, go radio-silent, or alter convoy patterns — that behavioral deviation from baseline is the signal. Palantir’s Gotham product was built precisely for this kind of pattern-of-life analysis.
- Financial Crime – A model trained on normal transaction behavior flags
accounts with sudden spikes in cross-border transfers, structuring behavior (many transactions just below reporting thresholds), or connections to flagged counterparties. - Pandemic / Biosurveillance – Unusual spikes in hospital admissions, pharmacy purchases of specific drugs, or search query patterns in a geographic cluster — all deviating from seasonal baseline models — can indicate an emerging outbreak before it is officially reported.
- Supply Chain / Critical Infrastructure – Unusual procurement patterns
a state actor quietly buying large quantities of specific industrial components that have dual military use — flagged against a baseline of normal trade flows.
The common thread across all of these is exactly what you described:
a very large, noisy dataset, a model of what normal looks like, and a pipeline that continuously scores incoming data and surfaces the deviations for human analysts to act on. That is the Palantir loop — ingest, model, detect, operationalize, act.
<!– See the working text for this QS in
00 
26.0721 (v1 26.0721)