Buckets:
| Name | Size | Uploaded | Xet hash |
|---|---|---|---|
| data | 10 items | ||
| indexes | 2 items | ||
| sample | 1 items | ||
| .gitattributes | 2.56 kB xet | 6645b98e | |
| README.md | 6.02 kB xet | 3f768df7 | |
| RESULTS.md | 2.56 kB xet | 9a794526 | |
| audit.json | 14.4 kB xet | e20e9759 | |
| calibration_targets.json | 1.68 kB xet | 13013b06 | |
| manifest.json | 2.69 kB xet | 6b3f8b9e | |
| persona_codes.schema.json | 326 kB xet | 2b1f7b8f |
MatrAIx Persona 1M
999,847 personas, each described by 1,290 categorical attributes. 599,847 are derived from real records, 400,000 are synthetic. 10 Zstandard Parquet shards, 4.17 GB.
Read it with pyarrow, not datasets
Attributes are packed: one persona's 1,290 attributes are 645 bytes of 4-bit
codes, low nibble first. datasets cannot open these files at all. Use pyarrow
and decode against persona_codes.schema.json.
import json, pyarrow.parquet as pq
schema = json.load(open("persona_codes.schema.json"))["columns"] # 1,290 entries
table = pq.read_table("data/persona-1m-0000.parquet") # 100,000 personas
def decode(attributes, null_bitmap):
"""One row -> {field id: value}. Missing attributes are omitted."""
out = {}
for i, col in enumerate(schema):
if null_bitmap is not None and (null_bitmap[i // 8] >> (i % 8)) & 1:
continue # bit set = missing
code = (attributes[i // 2] & 0x0F) if i % 2 == 0 else (attributes[i // 2] >> 4)
if code < len(col["values"]):
out[col["id"]] = col["values"][code]
return out
person = decode(table["attributes"][1].as_py(), table["null_bitmap"][1].as_py())
person.get("age_bracket"), person.get("region")
Three things to get right:
- Use
.get(), not[...]. Rows are sparse: 656 of 1,290 attributes are populated on average, andage_bracketfor instance appears in about a fifth of rows. Missing means the source did not support it; nothing is imputed. - In
null_bitmap, a set bit means missing, LSB first. A null bitmap means nothing is missing in that row. attribute_overridesbeats the decoded code. It holds exact values that fall outside the current codebook.
To filter without scanning 4 GB, indexes/postings.sqlite maps each value to the
global row ids that carry it.
Columns
| Column | |
|---|---|
source, source_row_index, source_record_id |
Provenance |
attributes |
645 packed bytes, the 1,290 attributes |
null_bitmap |
Missing-attribute bitmap; null means nothing missing |
attribute_overrides |
Exact values outside the codebook |
populated_attribute_count |
Non-null attributes in this row |
has_description, description_count, descriptions |
Field-level text. Synthetic personas carry none |
grounding |
Per-field evidence, confidence, assignment type |
metadata_json |
Source-specific metadata |
Files
| Path | |
|---|---|
data/persona-1m-0000..0009.parquet |
The personas. Nine shards of 100,000, one of 99,847 |
persona_codes.schema.json |
The codebook: 1,290 fields, their values, the packing spec |
indexes/postings.sqlite |
Value to row-id postings, plus indexes/manifest.json for shard offsets |
manifest.json |
Rows, bytes and SHA-256 per shard |
calibration_targets.json, audit.json, RESULTS.md |
Calibration contract, achieved margins, build summary |
sample/sample.parquet |
999 personas x 990 attributes, decoded. What the Dataset Viewer shows; not part of the release |
What the viewer shows
The viewer cannot read the packed shards, so it is pointed at sample/ instead:
999 personas as rows, 990 attribute ids as columns, each cell the decoded
value. All seven sources appear. Columns run densest first, and rows are
ordered by how many attributes are populated, so the table opens full and
thins out further down.
How much a persona carries depends on where it came from. Synthetic personas are complete by construction; a persona extracted from one Amazon review supports around 16 attributes. A blank cell is an attribute the source did not support, never an imputed one.
| Source | Rows in sample | Median attributes populated |
|---|---|---|
synthetic |
395 | 990 of 990 |
real_human_survey |
4 | 990 |
wiki |
320 | 388 |
prism |
6 | 144 |
stackoverflow |
113 | 68 |
amazon |
97 | 16 |
gss |
64 | 12 |
300 of the 1,290 fields are left out: the Dataset Viewer refuses more than 1,000 columns. The release carries all of them.
The release is 999,847 personas, not the 999 rows shown above. The row count
on this page, and anything load_dataset returns, describes that sample.
Composition
| Source | Rows |
|---|---|
| Wiki extraction | 323,438 |
| Stack Overflow survey | 113,120 |
| Amazon review extraction | 97,915 |
| GSS | 63,532 |
| PRISM Alignment | 1,487 |
| Real Human Survey | 355 |
| Full-DAG synthetic | 400,000 |
Four dimensions are calibrated against 2024 global population margins:
age_bracket and region from UN WPP 2024, gender_identity and urbanicity
from UN and World Bank totals with a schema prior over the remaining categories.
Build is deterministic for seed 20260720. audit.json reports achieved versus
target share per category; RESULTS.md summarises the build.
Limits
- Not a representative sample of any population. Calibration matches one-dimensional margins among rows where the field is known. It does not fix the joint distribution or remove source-selection bias.
- "Human-grounded" is not "verified". Wiki, Amazon, Stack Overflow and PRISM attributes come from model extraction and can carry extraction errors; GSS and survey mappings depend on crosswalk quality. Descriptions are model-generated.
- The 60/40 human-to-synthetic split is a design choice, not an estimate of any real ratio.
- Under-18 records were removed. 153 of the original 508 Real Human Survey records declared an age bracket under 18 and are gone; every count here reflects that, which is why the total is 999,847 rather than 1,000,000.
Source licenses and terms continue to apply to the underlying data.
- Total size
- 6.8 GB
- Files
- 20
- Last updated
- Aug 12
- Pre-warmed CDN
- US EU US EU