Co-Occurrence Network Construction and Manipulation
Overview
Constructs co-occurrence networks from several types of input data, such as delimited fields, long/bipartite tables, binary matrices, or wide sequences. Returns tidy edge data frames and supports optional scaling, splitting into several networks, thresholding, and subsetting. Provides eight similarity measures, including Jaccard, cosine, and association strength. Supports export to several network and file formats. Network construction and analysis methods follow Saqr, Lopez-Pernas, Conde, and Hernandez-Garcia (2024, doi:10.1007/978-3-031-54464-4_15).
cooccurrence()gains awindow =parameter for sliding-window co-occurrence on ordered sequence input (lists of vectors and wide TraMineR-style data frames viafield = "all"). Each window ofwconsecutive positions becomes one transaction; states inside the same window co-occur.window = sequence_lengthreduces to the existing bag-of-states behavior. TraMineR void markers (NA,"","%","*","NaN") are dropped before windowing. Pure base R viaembed().cooccurrence()gainsaggregate_by =andaggregate =parameters.aggregate_bygroups the data by a column (e.g. journal id), computes the per-group co-occurrence network with whateversimilarity/counting/scale/windowwas chosen, then combines the per-group edge weights into ONE final network.aggregate = c("sum", "mean", "min", "max")controls the combiner;countis always summed. Differs fromsplit_by, which keeps groups separate. Cannot be combined withsplit_by.thresholdandtop_napply after aggregation.
Show all changes in 0.4.0Hide the rest of the changes in 0.4.0
counting = "attention"adds positional gap-decay weighting: each pair within an ordered transaction contributesexp(-|pos_i - pos_j| / lambda)to the edge. Closer positions give a stronger edge, distant pairs decay. Matches thetna::build_model(type = "attention")semantics, undirected. The newlambda =parameter (default1.0) controls the decay rate.group =is now accepted as an alias forsplit_by =.summary.cooccurrence()now returns a structured summary object with network size, density, mean degree, isolates, node-level degree and strength, and optional group-level summaries.print.cooccurrence()now shows a compact diagnostic header before the edge preview, including density, mean degree, isolates, method metadata, and top nodes.plot.cooccurrence(type = "degree")adds a base R degree-distribution plot.cooccurrence()accepts a raw event log directly viaaction =(the event column), with optionalactor =,time =,session =,order =, andtime_threshold =(default 900 seconds). The log is sessionized into ordered sequences and each session becomes one transaction, sowindow =andcounting = "attention"apply. Sessionization — timestamp parsing and gap splitting — is delegated toNestimate::prepare()rather than reimplemented, soNestimateis required for this input only.cooccurrence()gainsvars =, naming the indicator (one-hot) columns directly. The specification is resolved likeselectin basesubset(), so a bare range (vars = A:D), bare names (vars = c(A, B, C)), positions (vars = 2:5), negative selection (vars = -c(id, note)), a logical mask, and a plain character vector all work. Other columns — ids, timestamps, metadata — are ignored, so a one-hot table no longer has to be stripped down to a bare matrix first. Cell values are read as presence, so count tables such as document-term matrices work alongside0/1andTRUE/FALSE.- Logical (
TRUE/FALSE) indicator tables are now auto-detected; previously only numeric0/1was recognized. NAin an indicator table is treated as absent. It previously reachedMatrix::sparseMatrix()as anNAindex and failed with an internal error.cooccurrence()accepts anestimate_dataobject fromNestimate::prepare()and uses itssequence_data, so event logs can be sessionized byprepare()(time gaps, timestamp parsing) and networked here without duplicating that logic. Passing one used to fall into the list-of-transactions branch and silently produce items built from the object's internal components.- Bug fix: unknown arguments were silently swallowed by
..., so a typo such assimliarity = "jaccard"returned raw counts with no warning. Unknown or unnamed arguments now raise an error. as.data.frame()on asummary.cooccurrenceobject returns tidy node-level metrics (what = "nodes", the default) or group-level metrics (what = "groups"), so callers no longer reach into the summary object's internals.similarity = "relative"is asymmetric, so each direction is now thresholded on its own value. Filtering by the undirected pair could retain a direction whose weight was belowthreshold.- Added a cross-implementation test suite pinning
cooccurrence()toNestimate::cooccurrence()across all eight similarity measures, all five shared input formats,min_occur,threshold,top_n, their combinations, degenerate inputs, and randomized networks. The two agree exactly once conventions are aligned: Nestimate stores item frequency on the matrix diagonal (diagonal = TRUE) where cooccure zeroes it, and Nestimate keeps every edge tied at thetop_ncut where cooccure truncates strictly at N. - Bug fix:
weight_bycombined withmin_occur > 1errored with "'dims' must contain all (i,j) pairs". The binary companion matrix was built from unfiltered column indices against filtered dimensions. - Bug fix:
min_occursupport for weighted input counted rows rather than distinct documents, so duplicate rows for one document could keep an item that appears in only that document. - Bug fix:
thresholdandtop_nfiltered the edge list but not the stored matrix, soas_matrix(), the heatmap, and the cograph and netobject converters disagreed with the printed edges (top_n = 1returned one edge but a three-edge matrix). The matrix is now rebuilt from the surviving edges. - Bug fix: with
counting = "attention", a window covering the whole sequence did not reproduce the unwindowed result.embed()emits each window most-recent-first, and attention reads positional gaps off the transaction, so the decay was mirrored. Windows are restored to reading order before deduplication; set-based counting is unaffected. as_igraph()andas_matrix()now acceptoutput = "gephi"objects, whose columns are namedSource/Target/Weight/Count. They previously failed with "undefined columns selected".- A group that fails during
split_bynow warns and names the group. Genuinely edgeless groups are still dropped quietly. threshold = 0is documented as meaning no filtering rather than "drop negative weights", so centering scalings such asscale = "zscore"keep their negative half.- Bug fix: the argument order now reproduces the CRAN 0.1.1 signature for its first thirteen arguments, so positional calls written against 0.1.1 keep their meaning. Arguments added in 0.1.2 (
vars, the event-log arguments,group,aggregate_by,aggregate,window,lambda) follow them. - Bug fix: a column repeated in
varswas counted twice by the sparse builder, inflating weight and count for every pair involving it. Selected columns are now deduplicated. - Bug fix: a
split_byresult inherited the FIRST group'smatrix,items,frequencies, andn_transactionsattributes fromrbind(), soas_matrix()and the other converters silently described only that group. Those attributes are now dropped from split results, andas_matrix()rebuilds from the full edge list. Per-group support is recorded in the newgroup_itemsandgroup_transactionsattributes. - Bug fix: the
groupsattribute of asplit_byresult listed every input level, including groups that produced no edges and were dropped from the data. It now lists only the groups present. - Bug fix: per-group density in
summary()counted only nodes that appear in an edge, so a group containing an isolated node reported a density above its true value (a group with edgeA-Bplus isolatedCreported density 1 instead of 1/3). - Bug fix:
summary()andprint()reported pooled simple-graph metrics forsplit_byresults, where a node pair can occur once per group. Density could exceed 1 and node degree could exceedn_nodes - 1.density,mean_degree, andpossible_edgesare nowNAfor split results, and the per-group table reports the correct values.
From NEWS.md in the release
Install
Health
- OK13 OK2026-08-05
- NOTE12 OK, 1 NOTE2026-08-01
- OK13 OK2026-06-09
- ERROR12 OK, 1 ERROR2026-06-08
- OK5 OK2026-04-25
Documentation
- Help pages
- 16
- Examples that run
- 100%15 run in a plain check (1 of them under a condition)
- Exported functions with examples
- 100%
- Documented parameters
- 99%
- Return-value docs
- 100%
- Help pages citing references
- 6%
Downloads
Repository
- PRs merged (all time)
- 100%
- Median days to close, 50 most recently updated closed issues
- not measured
- Median days to close, 50 most recently updated closed PRs
- 1
Stars over time
Forks over time
PRs over time
Commits over time
5 development-tooling and community-health practices detected across 3 families in the upstream repository
Checks run against github.com/mohsaqr/cooccure on 2026-10-21.
GitHub Pages site last deployed 2026-10-08 · The repository has a site deploy workflow
This repository shows signs of AI coding tools.
- Claude Codefirst seen 2026-04-16Named in .Rbuildignore: .claude, CLAUDE.mdNamed in .gitignore: .claude, CLAUDE.mdCommits: at least 34 crediting it in the message
- Claude Sonnet 4.616 commits · Apr 2026
- Claude Opus 4.610 commits · Apr 2026
- Claude Opus 4.78 commits · Apr 2026
Dependencies
Installing cooccure adds no packages beyond those that come with R.
Code & Tests
Datasets
People & History
Pick two releases to compare their code metrics.
- 0.4.0Latest
- 0.1.12026-04-24
- RR 4.6.0 released · 2026-04-24
- RR 4.5.0 released · 2025-04-11
Package metadata
- First published
- 2026-04-24
- Total releases
- 2 / 1 yrs
- License
- MIT + file LICENSE OSI
- Minimum R
- ≥ 3.5.0
- Bundled data
- 49 KB / 4 files
- Download size
- 846 KB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("cooccure")This package has no citation file, so citation() returns this entry built from DESCRIPTION.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-24, which the citation names so these numbers can be found later. More on citing and the projects behind them.