Post cards connect to two term groups and a joint-presence grid.
Compare target posts with a separate background group.

A term is a word you chose before the count. The target term is the word you follow. A partner term is a second word you test beside it. A term pair is those two terms. Co-occurrence means both terms occur in the same post. An eligible post is one distinct post with complete text inside your frame. The frame is your date scope plus your exact URL list.

The joint count is the number of eligible posts that contain both terms. The conditional share equals the joint count divided by the number of target posts. The background share equals the partner count among the other posts divided by the number of those other posts. The denominator is the number you divide by. A share with no denominator is undefined.

The result is a set of term flags, a pair table, both shares, and a ledger of missing text. A ledger is your saved list of attempts that stay out of the count. Describe this supplied sample only.

1. Define the frame

Write the target term and each partner term before you collect posts. Write the publication dates you intend to include. Write the exact known URLs that form the frame.

This count says which partner terms occur with the target in that supplied sample. It does not build a history of use over time. It is not a search service for every post on X.

Write these choices first. If you pick partner terms after you see the words, you may favor a pattern you already noticed.

2. Collect known public posts

An Actor is a hosted program that collects source rows. A Task is a saved input for an Actor. A run is one execution of the Actor.

Use the X Post Metrics Actor, public build 1.0.4. The current Task is X Post Analytics Snapshot. The Task stores a starting input. It does not count terms for you. A saved Task does not prove that the count is automatic.

This build reads `startUrls`. Each value must be a known public post URL that contains `/status/`. The saved list has three sample URLs:

  • https://x.com/OpenAI/status/2074907025537224840
  • https://x.com/OpenAI/status/2074907027378511884
  • https://x.com/OpenAI/status/2074907031862190406

Replace the whole list with one public `/status/` URL you already know. Use that one URL for the first run. Do not add a search. Do not ask for post history. Do not set `maxItems`. This Actor does not return a complete archive. Add more known URLs only after you inspect the first row.

Each saved row can hold these fields:

2. Collect known public posts
FieldWhat it holds
`inputUrl`The URL you sent
`postUrl`The post URL on the row
`postId`The post ID
`postType`The post type
`publishedAt`The publication time
`text`The current post text
`profileUrl`The profile URL
`profileId`The profile ID
`profileUsername`The profile user name
`profileName`The profile display name
`status`The row status
`statusReason`The reason for that status
`observedAt`The time this row was observed

`text` can be null. Other facts on the row can be null too. Null means the value is missing. It does not mean the count is zero.

`postMetricStatus` is separate from `text`. It has one entry for each of six metrics. The metrics are views, likes, replies, reposts, quotes, and bookmarks. Each entry has its own status and its own precision. Precision means how exact that metric value is. Do not read the six entries as six levels of one scale. They do not prove that the text is complete.

OUTPUT is evidence about the run. It is not the term table. It names `inputCount`, `datasetRows`, `usefulRows`, `billableRows`, `failedRows`, `statusCounts`, and `stopReason`. `inputCount` is how many URLs the run received. `datasetRows` is how many rows were saved. `usefulRows` is the run total for useful rows. `billableRows` is the run total for billable rows. `failedRows` is the run total for failed rows. `statusCounts` groups rows by status. `stopReason` says why the run stopped. These totals are not the fields on each row.

A checked read of one known public OpenAI post returned the correct post ID and profile ID. It returned the publication time and the current counters. The text was present and not blank. The text had 200 characters. This article does not copy that text. OUTPUT for that check was `inputCount` 1, `datasetRows` 1, `usefulRows` 1, `billableRows` 1, and `failedRows` 0. `statusCounts` was ok 1. `stopReason` was `inputs_exhausted`.

That result shows text support for one known public post. It does not prove the same result for every URL. It does not prove that image text was read. It does not prove that a quote body, a linked page, or speech in a video was read. Hidden or restricted portions need a separate check. A status of ok does not prove the text is enough for your count. Text of 200 characters does not prove that the row holds the whole post.

Match rows on `postId` so one post is one unit. Keep `publishedAt` and `observedAt`. If the post ID is missing, give that attempt its own state. If the source fails, give that attempt its own state. If your frame uses dates, an unknown `publishedAt` is not a known date inside the window. Keep that attempt out of the date-limited count until the date is known. Do not turn a missing fact into a word count of zero.

3. Decide whether the text is complete

This question uses post text only. For each row, write whether the text is complete enough to count. Save that note.

Do not treat a status of ok as proof of complete text. Do not treat `postMetricStatus` as that proof. If `text` is missing or partial, keep the post out of the complete-text denominator. Add a separate copy only after you check that copy yourself.

Do not take words from an image. Do not take words from a linked page. Do not take words from a video. A successful row status can still leave this text question unanswered.

The `text` field is the wording observed at `observedAt`. That wording can differ from older wording if the post was edited. It can also omit a portion. If that difference would change your count, keep the current text apart from any older copy. Do not merge them without a written choice.

4. Write the term rule before you count

Use one literal rule, and write it down before the first flag. For the English example in this article, the rule is fixed.

Ignore letter case. Match whole words only. A whole word has a boundary at each side, or it sits at the start or end of the text. A boundary is the edge of a word. Spaces are boundaries. A period, comma, or quote mark is also a boundary. The mark is not part of the word. Under this rule, the characters timer. match the term timer.

Do not stem words. A stem is a shortened root. Do not count a synonym as the same term. Keep the raw text unchanged. A phrase of two or more words needs its own written rule. Another writing script needs its own rule. A link or an alias needs its own rule. Test that rule on the raw text before you use it.

A whole-word match does not mean the author supports the term. It does not prove which real thing the word names.

5. Set one flag on each eligible post

A binary flag is 1 or 0. Use 1 when the eligible text contains the term under your rule. Use 0 when that complete text does not contain it. Make one flag per term per distinct eligible post.

The post is the unit. If the term appears five times in one post, the flag is still 1. Those repeats describe the writing inside the post. They do not add posts. An exact repeat of the same export does not add a post either.

If two versions of one post disagree, choose the source before you count. Record the choice. Record any denominator that changes. Do not keep both versions as two posts.

6. Build the 2-by-2 table

Choose one partner and sort every eligible post into four cells. A cell is one of the four counts. The cells are both terms, target only, partner only, and neither term.

Report n, the target-positive count, the partner-positive count, and the joint count. n is the number of eligible posts.

Use these plain formulas:

conditional share = joint count / target-positive count

background share = partner posts without the target / posts without the target

The conditional share is the partner share among target posts. The background share is the partner share among posts that lack the target.

If the target-positive count is 0, the conditional share is undefined. If the posts without the target are 0, the background share is undefined. Leave the share blank. Do not write 0 to fill it. A written 0 would claim a measurement of an empty group.

7. Compare the shares in view of the denominators

Show both fractions. A large conditional share can belong to a common word. The background share shows that possibility. Many joint matches do not prove a specific connection.

This sample is small, and you chose the URLs. It cannot stand for all of X. It cannot show cause. It cannot show how many posts use the term on X. It cannot show how fast a pattern changes. It cannot show statistical significance. That name means a formal test against chance. This table is not that test.

The author may quote a term without supporting it. A review of meaning is a separate task. Use the shares as a description of these eligible posts.

8. Save the count and name the limit

Save the term flags, the pair table, the written rule, and the exclusion ledger. A reader can rebuild each denominator only when those pieces are saved.

If you need every matching post over time, say what this sample cannot do. A known URL list is not that full set. Use the sample to inspect a stated idea. Then improve the written frame. Do not present the table as a trend for all of X.

Work the same rules on original fiction

Original fiction starts here. The posts, IDs, and counts below are a teaching example. They are not an Actor result. They are not OUTPUT. They do not estimate language on X. They do not show cause.

Each post has a distinct fictional ID and complete text under the rule above. These IDs are not real X post IDs. Case does not matter, so Job matches job. A sentence period is a boundary. Job sits at the start, so the start of the text is a boundary. No word here merely hides retry, timer, or job inside a longer word.

Work the same rules on original fiction
IDCurrent fictional textretrytimerjob
F1Job retry uses a timer.111
F2Job retry checks the timer.111
F3Job retry waits for a timer.111
F4Job retry cancels the timer.111
F5Job retry adds a log.101
F6Job retry follows the rule.101
F7Job timer logs a message.011
F8Job log records a message.001
F9Job rule records a message.001
F10Job workers send a message.001

The first four posts have retry, timer, and job. The next two have retry and job, but not timer. The seventh has timer and job, but not retry. The last three have job only.

Add the flags. Retry sums to 6. Timer sums to 5. Job sums to 10. Both retry and timer are 1 on F1, F2, F3, and F4. The joint count is 4.

The retry and timer table is:

Work the same rules on original fiction
target termtimer 1timer 0Row total
retry 1426
retry 0134
Column total5510

n is 10. The target-positive count is 6. The partner-positive count is 5. The joint count is 4. The four cells are 4, 2, 1, and 3.

The conditional share is 4/6. That fraction rounds to 66.7 percent. The denominator is the six posts in the retry 1 row. Do not divide 4 by all 10 posts.

The background share is 1/4, which is 25 percent. The denominator is the four posts in the retry 0 row. Only F7 in that row has timer. The column total under timer 0 is 5. That is a different total. Do not use 5 as this denominator.

The retry and job table uses the same ten posts:

Work the same rules on original fiction
target termjob 1job 0Row total
retry 1606
retry 0404
Column total10010

The joint count for retry and job is 6. The conditional share is 6/6, which is 100 percent. The background share is 4/4, which is 100 percent. Job has more joint matches than timer. Timer has 4. Job has 6. The two job shares are equal, so job shows no contrast in this example. The cells with 0 are real absences in complete text. They are not missing text.

Two more source attempts have no text. Keep them in a reader ledger. Do not call them F11 and F12. Do not put them in the neither cell. Do not copy this ledger into OUTPUT. Do not treat it as `failedRows`. Missing text is unknown. It is not a false flag. It is not a native failure you may infer from an absent word.

Work the same rules on original fiction
AttemptTextretrytimerjobEligibleReason
S1unavailableunknownunknownunknownnoThe text is missing, so every flag is unknown. This attempt is not a negative post.
S2unavailableunknownunknownunknownnoThe text is missing, so every flag is unknown. This attempt is not a negative post.

The collection has 12 source attempts. Ten are distinct eligible posts with complete text. Two attempts have unavailable text. The complete-text denominator stays 10.

If a target group had 0 eligible posts, its conditional share would be undefined. If the background group had 0 posts, that share would be undefined too. Write undefined. Do not invent 0 percent.

Read 4/6 beside 1/4 for this example only. The gap describes these ten sentences. It does not describe all of X. It does not show cause, significance, or a trend. Job shows why the second share matters. Its joint count is larger, but both of its shares are 100 percent.

Sources & further reading

By Chronometrica · Updated

Back to top ↑