---
title: 'User Profiles'
source: 'https://academia.sh/en/courses/user-experience/user-profiles'
course: 'User Experience and Behavior Design'
language: en
updated: '2026-08-19T05:19:59+00:00'
license: 'CC BY-SA 4.0'
---

# User Profiles

That a persona is not a fabricated person but a behavior set derived from data; clustering participants, calculating the explanatory power of role-based grouping, and the ethical limit of a persona.

The previous lesson pulled ten codes out of twelve interviews, but still left the
participants as a list in the form `P01`–`P12`. No design decision can be made with this
list: twelve separate people do not get twelve separate interfaces. Seeing the list's
structure is necessary to make a decision — who resembles whom, along which axis, and
does that axis change the design?

The common answer to this question is wrong. Participants are usually grouped by role:
undergraduate student, graduate student, faculty member, library staff member, external
member. This grouping looks manageable because roles are already on record. This lesson
compares two groupings on the same data and calculates how much of the behavior role
actually explains.

## What a Persona Is and Is Not

A **persona** is a definition derived from research data that represents a set of
behaviors. It has three parts:

- **Goal:** the reason the person uses the interface. "Browsing sources" and "finding a
  known book" are separate goals, and they produce separate interface decisions.
- **Behavior:** the observed form of the goal. Session duration, search type, borrowing
  frequency, which screen they entered from.
- **Constraint:** conditions the person cannot change. Time, screen, language,
  accessibility requirement.

When a persona contains anything outside these three, it stops producing design
decisions. A made-up name, an age, a photograph, and a life story try to make the persona
look "alive," but no decision can be grounded in these details. In the catalog
interface, the decision of how many rows the result list shows depends on whether the
user's session lasts four minutes or twenty-two, not on whether the user is thirty-two or
forty-five years old.

The criterion is this: a design decision must be demonstrable for every line written in
the persona. A line with no corresponding decision is removed from the persona.

## Clustering Participants by What Is Measured

Four measures were extracted from the observation sessions: the share of a session spent
on subject browsing, the average session duration, the monthly borrow count, and the
share of sessions entered from a narrow screen. Because these measures are on different
scales, they are first moved into a common range, then the distance between participants
is calculated, and the ones close to each other are merged.

```js
// profile.mjs — comparing grouping by behavior with grouping by role

// Measures derived from observation sessions (data constructed for this lesson).
// browse: share of session spent on subject browsing, duration: average session minutes,
// borrows: monthly borrow count, narrowScreen: share of sessions on a narrow screen.
const PARTICIPANTS = [
  { id: "P01", role: "undergraduate", browse: 0.15, duration: 4,  borrows: 6, narrowScreen: 0.10 },
  { id: "P02", role: "graduate",      browse: 0.85, duration: 22, borrows: 2, narrowScreen: 0.20 },
  { id: "P03", role: "undergraduate", browse: 0.45, duration: 6,  borrows: 2, narrowScreen: 0.85 },
  { id: "P04", role: "undergraduate", browse: 0.80, duration: 19, borrows: 3, narrowScreen: 0.15 },
  { id: "P05", role: "faculty",       browse: 0.20, duration: 5,  borrows: 8, narrowScreen: 0.05 },
  { id: "P06", role: "external",      browse: 0.50, duration: 7,  borrows: 1, narrowScreen: 0.90 },
  { id: "P07", role: "staff",         browse: 0.40, duration: 5,  borrows: 3, narrowScreen: 0.80 },
  { id: "P08", role: "staff",         browse: 0.10, duration: 3,  borrows: 7, narrowScreen: 0.15 },
  { id: "P09", role: "faculty",       browse: 0.90, duration: 25, borrows: 2, narrowScreen: 0.10 },
  { id: "P10", role: "graduate",      browse: 0.48, duration: 8,  borrows: 2, narrowScreen: 0.88 },
  { id: "P11", role: "external",      browse: 0.78, duration: 20, borrows: 1, narrowScreen: 0.25 },
  { id: "P12", role: "graduate",      browse: 0.18, duration: 5,  borrows: 6, narrowScreen: 0.12 },
];
const MEASURES = ["browse", "duration", "borrows", "narrowScreen"];

// Measures are on different scales; move each into the 0-1 range.
const min = {}, max = {};
for (const m of MEASURES) {
  min[m] = Math.min(...PARTICIPANTS.map((p) => p[m]));
  max[m] = Math.max(...PARTICIPANTS.map((p) => p[m]));
}
const vector = (p) => MEASURES.map((m) => (p[m] - min[m]) / (max[m] - min[m]));
const V = PARTICIPANTS.map(vector);
const distance = (a, b) => Math.hypot(...a.map((v, i) => v - b[i]));

// Agglomerative clustering with complete linkage: merge the two nearest clusters, stop at k clusters.
function cluster(target) {
  let clusters = V.map((_, i) => [i]);
  while (clusters.length > target) {
    let best = [0, 1], smallest = Infinity;
    for (let i = 0; i < clusters.length; i++)
      for (let j = i + 1; j < clusters.length; j++) {
        let d = 0;
        for (const a of clusters[i]) for (const b of clusters[j]) d = Math.max(d, distance(V[a], V[b]));
        if (d < smallest) { smallest = d; best = [i, j]; }
      }
    const [i, j] = best;
    clusters = clusters.filter((_, x) => x !== i && x !== j).concat([clusters[i].concat(clusters[j])]);
  }
  return clusters.map((c) => c.sort((a, b) => a - b)).sort((a, b) => a[0] - b[0]);
}

// Within-cluster sum of squares: each member's squared distance to the cluster mean
const sumOfSquares = (groups) =>
  groups.reduce((t, g) => {
    const avg = MEASURES.map((_, d) => g.reduce((s, i) => s + V[i][d], 0) / g.length);
    return t + g.reduce((s, i) => s + distance(V[i], avg) ** 2, 0);
  }, 0);

const TOTAL = sumOfSquares([PARTICIPANTS.map((_, i) => i)]);
const roleGroups = [...new Set(PARTICIPANTS.map((p) => p.role))].map((r) =>
  PARTICIPANTS.map((p, i) => [p, i]).filter(([p]) => p.role === r).map(([, i]) => i)
);
const behaviorGroups = cluster(3);

console.log("clusters by behavior (k = 3)");
for (const g of behaviorGroups) {
  const avg = MEASURES.map((_, d) => g.reduce((s, i) => s + PARTICIPANTS[i][MEASURES[d]], 0) / g.length);
  console.log(
    `  ${g.map((i) => PARTICIPANTS[i].id).join(" ").padEnd(20)} n=${g.length}  ` +
      `browse ${avg[0].toFixed(2)}  duration ${avg[1].toFixed(1)} min  borrows ${avg[2].toFixed(1)}  narrow screen ${avg[3].toFixed(2)}`
  );
  console.log(`     roles: ${[...new Set(g.map((i) => PARTICIPANTS[i].role))].sort().join(", ")}`);
}

console.log("\ngroups by role");
for (const g of roleGroups) {
  console.log(`  ${PARTICIPANTS[g[0]].role.padEnd(14)} ${g.map((i) => PARTICIPANTS[i].id).join(" ").padEnd(16)} n=${g.length}`);
}

const roleSS = sumOfSquares(roleGroups), behaviorSS = sumOfSquares(behaviorGroups);
console.log("\ngrouping          groups  within-cluster sum of squares  explained variance");
console.log(`by role           ${String(roleGroups.length).padStart(6)}  ${roleSS.toFixed(3).padStart(28)}  ${((1 - roleSS / TOTAL) * 100).toFixed(1)}%`);
console.log(`by behavior       ${String(behaviorGroups.length).padStart(6)}  ${behaviorSS.toFixed(3).padStart(28)}  ${((1 - behaviorSS / TOTAL) * 100).toFixed(1)}%`);
console.log(`total variance (single group): ${TOTAL.toFixed(3)}`);

// Each cluster's medoid: the member whose distance sum within the cluster is smallest
console.log("\ncluster  medoid  within-cluster distance sum");
for (const g of behaviorGroups) {
  const scores = g.map((i) => [i, g.reduce((s, j) => s + distance(V[i], V[j]), 0)]);
  scores.sort((a, b) => a[1] - b[1]);
  console.log(`${g.map((i) => PARTICIPANTS[i].id).join("+").padEnd(20)} ${PARTICIPANTS[scores[0][0]].id}  ${scores[0][1].toFixed(3)}`);
}
```

```
clusters by behavior (k = 3)
  P01 P05 P08 P12      n=4  browse 0.16  duration 4.3 min  borrows 6.8  narrow screen 0.11
     roles: faculty, graduate, staff, undergraduate
  P02 P04 P09 P11      n=4  browse 0.83  duration 21.5 min  borrows 2.0  narrow screen 0.17
     roles: external, faculty, graduate, undergraduate
  P03 P06 P07 P10      n=4  browse 0.46  duration 6.5 min  borrows 2.0  narrow screen 0.86
     roles: external, graduate, staff, undergraduate

groups by role
  undergraduate  P01 P03 P04      n=3
  graduate       P02 P10 P12      n=3
  faculty        P05 P09          n=2
  external       P06 P11          n=2
  staff          P07 P08          n=2

grouping          groups  within-cluster sum of squares  explained variance
by role                5                         4.885  22.3%
by behavior            3                         0.261  95.8%
total variance (single group): 6.286

cluster  medoid  within-cluster distance sum
P01+P05+P08+P12      P01  0.538
P02+P04+P09+P11      P02  0.605
P03+P06+P07+P10      P03  0.450
```

## Role Is Not a Persona

The result of the comparison reads in a single line. Grouping by role produces **five**
groups and explains 22.3% of the variance in behavior; grouping by behavior explains
95.8% with **three** groups. This comparison favors role, because more groups always tend
to produce smaller within-group variance. Higher explanation with fewer groups shows that
the difference comes from the data.

The reason shows up in the composition of the clusters: each of the three behavior
clusters contains four distinct roles. Two people with the same role do not resemble each
other; four people with different roles do. Undergraduate P01 and faculty member P05 are
in the same cluster — both want to find a known record and leave. Undergraduate P04 and
faculty member P09 are in another cluster — both browse by subject. Role is cheap to
measure because it is already written in the library record; it has no counterpart in
design because it does not explain behavior.

The averages of the three clusters give the core of the personas.

- **Known-Record Searcher.** Subject-browsing share 0.16, session 4.3 minutes, 6.8
  borrows a month. For this persona, the first row of the result list is decisive; the
  user does not scan the list, they confirm the first match and leave.
- **Subject Browser.** Subject-browsing share 0.83, session 21.5 minutes, 2.0 borrows a
  month. This persona actually reads the list, compares, and leaves without borrowing in
  most sessions. What matters to them is not the transaction but being able to return to
  the list.
- **Narrow-Screen Viewer.** 0.86 of sessions on a narrow screen, duration 6.5 minutes.
  This persona's constraint is the screen: the same result list shows them fewer rows,
  and the same action bar does not fit.

The third table gives each cluster's **medoid**: the member whose within-cluster distance
sum is smallest. When the persona text is written, this participant's notes are used,
because it is a real record standing at the center of the cluster. It is not an average
person; it is the person closest to the average.

## The Ethical Limit of a Persona

Because a persona is derived from research data, it inherits every obligation that
participant data carries.

**A single-member cluster is not a persona.** If a cluster reduces to a single member,
that persona is one person's behavior record; even with the name removed, someone on the
team recognizes it. The rule is this: if a persona does not represent the behavior of at
least three participants, it is not written as a persona — it stays an observation. All
three clusters above have four members.

**The medoid's quote is anonymized too.** When a participant's words are brought into the
persona text, details that would make the person identifiable are removed. The criterion
set in the previous lesson applies here as well: it must not be possible to trace back
from the data to identity.

**The persona stays within the scope of consent.** When the participant joined the
research, they consented to their data being used in design decisions, not to their name
appearing on a persona card. This is the only defensible reason for giving personas
made-up names, but the made-up name is also chosen so that it does not evoke the real
one.

**A persona must not turn into a tool for exclusion.** The sentence "this persona is not
our user" can be written as a scope decision, but it is written together with who was not
measured. If none of the three personas were derived from a participant who uses a screen
reader, that is not a finding but a sample gap, and it is recorded in the persona
document as such.

## Summary

- A persona is the triad of goal, behavior, and constraint; a design decision must be
  demonstrable for every line in the persona.
- Participants are clustered by measured behavior; the measures are moved into a common
  range and merged by distance.
- In the sample data, grouping by role explained 22.3% of the variance with five groups,
  and grouping by behavior explained 95.8% with three groups; role is cheap to measure
  but does not explain behavior.
- Each cluster's medoid is the real participant whose within-cluster distance sum is
  smallest; the persona text is written from this record, not from an average person.
- A persona is not written unless it represents at least three participants; a persona
  must not make a participant re-identifiable, and it must not present those left outside
  the sample as a finding.

## Next Step

Three personas were obtained, but a persona alone is not a to-do list. The Subject
Browser persona's session lasts twenty-one minutes — what exactly do they do in that
time, which steps do they follow in order, and what should be expected at each step? The
next lesson turns the need into action: it addresses the form in which a user story is
written, how a solution seeps into it, and how tasks are ranked by frequency and failure
data.
