scDist 扰动距离

SKILLAI 工具
AI 工具 未标注权限 许可证不明确
安装这个技能

Chat2Research Al科研工作台:Use when quantifying per-cell-type perturbation distance between conditions with scDist. Ranks cell types by how far their transcriptome shifts, absorbing sample/patient effects.(Skill由Chat2Research Al科研工作台:https://icell.abiosciences.cn/?source=20e0489c 提供,登录平台可享免费算力和Token及更多分析组学Skills)

一句话选型结论

按资料字段整理

scDist 扰动距离是AI 工具类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类AI 工具 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_7ece4fea/scdist-perturbation-distance
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

AI 工具
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_7ece4fea仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791623499
正文体量18.1 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
组合多个 AI 能力

把写作、检索、总结串成一条流程。

搭工作流

把固定流程做成可重复调用的步骤。

做提示词与评测

整理提示词并对比输出效果。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在AI 工具场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
scDist 扰动距离当前 未标注权限 未标注 未标注 未标注 有
执行计划 只读 GitHub 仓库 151.5 万 Codex、Claude、Cursor 有
Playwright MCP 测试 浏览器控制 ClawHub 市场 136.5 万 OpenClaw 有
完成前的验证 未标注权限 GitHub 仓库 131.9 万 Codex、Claude、Cursor 有
子 Agent 驱动开发 只读 GitHub 仓库 131.2 万 Codex、Claude、Cursor 有
前端设计 执行命令 GitHub 仓库 125.6 万 Codex、Claude、Cursor 有

SKILL.md 全文

18.1 KB
模型实际读到的说明书原文,来自技能仓库

scDist — Perturbation Distance Between Conditions (per cell type)

Overview

scDist estimates the distance between the two condition means of a cell type in
high-dimensional gene-expression space
. For each cell type you get one number
(Dist.), a 95% credible interval and a p-value — i.e. an answer to "which cell
types are most perturbed by the condition?"
, not "which genes changed?".

How it differs from differential expression (DE):

DE (pseudobulk / MAST / Wilcoxon) scDist
Unit of evidence one gene at a time the whole expression vector
Output thousands of gene-level logFC/p one distance + CI + p per cell type
Sample variability handled via design matrix per gene linear mixed-effects model per PC, (1|sample) random intercept absorbs patient/sample effects
Multiplicity burden large (FDR over genes) small (one test per cell type)
Failure mode a few noisy genes can dominate aggregated over PCs → more robust to single-gene noise

Internally: per cell type → PCA (irlba::prcomp_irlba, d PCs) on that cell type's
cells → for each PC fit lmer(y ~ condition + (1|random)) → the coefficient of the
condition per PC, shrunk with ashr, gives a posterior over the vector of
coefficients → Dist. = median of the posterior distance (L2 norm of the
condition effect vector across PCs); p-value is a Monte-Carlo test (10^5 reps) of
the summed Wald statistic.

Upstream (not on CRAN or Bioconductor — install from GitHub):

  • Repo: <https://github.com/phillipnicol/scDist> (default branch master, package version 1.1.5)
  • Install: Rscript -e &#x27;devtools::install_github(&quot;phillipnicol/scDist&quot;)&#x27;
  • Cite: Nicol PB, Paulson D, Qian G, Liu XS, Irizarry RA, Sahu AD (2024)
    Robust identification of perturbed cell types in single-cell RNA-seq data,
    Nature Communications 15:7610. <https://doi.org/10.1038/s41467-024-51649-3>

Verified signature (man/scDist.Rd + R/scDist.R on master, 2026-09):

scDist(normalized_counts, meta.data, fixed.effects, random.effects = c(),
       clusters, d = 20, truncate = FALSE, min.count.per.cell = 20, weights = NULL)

Inputs

scDist() takes two objects only — a matrix and a metadata table. There is no
Seurat method inside the package; the user converts the Seurat object themselves.

  1. normalized_counts — a matrix (or object coercible with as.matrix),
    genes on rows, cells on columns (the function transposes internally: the
    source comment is "Normalized counts currently in cells x genes" right before a
    t()). rownames (gene names) are required — the function stop()s
    without them. In practice pass Seurat's scale.data: NormalizeData() +
    ScaleData() output, which is already genes × cells, log-normalized and
    centered. Do not pass raw counts and do not pass a plain library-size-
    normalized matrix if a scale.data slot exists.
  2. meta.data — a data.frame with one row per cell, in the same cell order
    as the matrix columns
    . It must contain the three columns referenced below.

The three column arguments

Argument Meaning Typical value Rules
fixed.effects column(s) whose effect defines the distance. The first element is the condition of interest; any further elements are added as covariates &quot;response&quot; (e.g. responder vs non-responder) must have ≥2 levels overall and ≥2 levels inside each analysed cell type
random.effects column(s) put in as random intercepts (1|col); absorbs sample / patient / batch variability c(&quot;sample&quot;), c(&quot;patient&quot;) must have ≥2 levels; the whole point is that the same subject appears in both conditions — if every subject is in one condition only, condition and subject are confounded
clusters column holding the cell-type labels; scDist loops over its levels and analyses one cell type at a time &quot;subCluster1&quot; ≥ max(min.count.per.cell, d) cells per level, ≥2 levels of every fixed/random effect inside that level

Ordering matters for fixed.effects: the design is
y ~ fixed.effects[1] + ... + (1|random.effects[1]) + ... and the code reads the
condition coefficient as summary(fit)$coefficients[2, ]. Always put the
condition first; extra fixed effects are covariates (design.null drops only
fixed.effects[1]).

Steps

Reusable script: scripts/scdist_perturbation_distance.R.txt — fully command-line
parameterised, no hard-coded paths. Defaults reproduce the original CD4T run
(d = 20, fixed.effects = &quot;response&quot;, random.effects = &quot;sample&quot;,
clusters = &quot;subCluster1&quot;).

  1. Inspect the object before running (cheap, avoids silent skips):
srt &lt;- readRDS(&quot;CD4T.seu.globalC.rds&quot;)
colnames(srt@meta.data)                       # confirm column names
table(srt$subCluster1)                        # cell-type sizes vs d
table(srt$response, srt$sample)               # design: is every subject in both arms?
dim(GetAssayData(srt, assay = &quot;RNA&quot;, layer = &quot;scale.data&quot;))   # Seurat v5
  1. Build the two inputs (exactly as in the original user script):
libme &lt;- list(
  Y         = as.matrix(srt@assays[[&quot;RNA&quot;]]@scale.data),  # genes x cells (Seurat v4)
  meta.data = as.data.frame(srt@meta.data)
)
dim(libme$Y)          # sanity: ncol(Y) == nrow(meta.data)
  1. Run scDist for one comparison, or once per condition subset:
out &lt;- scDist(normalized_counts = libme$Y,
              meta.data        = libme$meta.data,
              d                = 20,                    # PCs used
              fixed.effects    = &quot;response&quot;,            # condition of interest
              random.effects   = c(&quot;sample&quot;),           # absorb subject effect
              clusters         = &quot;subCluster1&quot;)         # cell-type column
  1. Take the results out — out$results is a data frame whose rownames are
    the cell-type labels
    :
out$results
#                  Dist. 95% CI (low) 95% CI (upper)      p.val
# CD4_Tn_CCR7          0            0      0.5700683 0.24810752
# CD4_Tcm_IL7R         0            0      0.0000000 0.08592914
# ...
out$design        # y ~ response + (1 | sample)   -&gt; confirms what was fitted
out$gene.names    # genes actually used (= nrow of the input matrix)
out$vals[[&quot;CD4_Tcm_IL7R&quot;]]$beta      # condition coefficient per PC
out$vals[[&quot;CD4_Tcm_IL7R&quot;]]$D.hat     # unshrunk estimate (vs out$results$Dist. = posterior median)
  1. Save and plot:
saveRDS(out, file = &quot;scDist.cd4t.Response.PRE.rds&quot;)

scDist::DistPlot(out)        # distance + 95% CI per cell type (built in)
scDist::FDRDistPlot(out)     # distance vs -log10(FDR) (built in)
scDist::distGenes(out, cluster = &quot;CD4_Tcm_IL7R&quot;)   # genes driving that cell type&#x27;s shift
  1. Typical PRE/POST/ALL workflow (the original analysis): run the script three
    times (all cells, time == &quot;pre&quot;, time == &quot;post&quot;), then merge the result
    tables — merge() appends suffixes .pre / .post, turning Dist. into
    Dist..pre and p.val into p.val.pre. A scatter of -log10(p.val.pre) vs
    -log10(p.val.post), with ggrepel::geom_text_repel() labels for cell types
    significant in either condition, is the published figure:
out.list &lt;- list(PRE  = readRDS(&quot;scDist.cd4t.Response.PRE.rds&quot;),
                 POST = readRDS(&quot;scDist.cd4t.Response.POST.rds&quot;),
                 ALL  = readRDS(&quot;scDist.cd4t.Response.ALL.rds&quot;))
out &lt;- merge(out.list$PRE$results  |&gt; tibble::rownames_to_column(&quot;sub&quot;),
             out.list$POST$results |&gt; tibble::rownames_to_column(&quot;sub&quot;),
             by = &quot;sub&quot;, suffixes = c(&quot;.pre&quot;, &quot;.post&quot;))
out &lt;- merge(out, out.list$ALL$results |&gt; tibble::rownames_to_column(&quot;sub&quot;), by = &quot;sub&quot;)

ggplot2::ggplot(out) +
  ggplot2::geom_point(ggplot2::aes(x = -log10(p.val.pre), y = -log10(p.val.post),
                                   size = -log10(p.val), col = sub), alpha = 0.5) +
  ggrepel::geom_text_repel(
    data = subset(out, p.val.pre &lt; 0.05 | p.val.post &lt; 0.05),
    ggplot2::aes(x = -log10(p.val.pre), y = -log10(p.val.post), label = sub, col = sub),
    size = 4, max.overlaps = 20, show.legend = FALSE, min.segment.length = 1) +
  ggplot2::theme_classic() + ggplot2::labs(x = &quot;PRE&quot;, y = &quot;POST&quot;) +
  ggplot2::ggtitle(&quot;Response&quot;)
  1. Command-line run of the bundled script (does steps 2–5 in one go):
# all cells; original parameters are the defaults
Rscript scripts/scdist_perturbation_distance.R.txt \
    --input-rds CD4T.seu.globalC.rds --output-dir out --prefix cd4t_response_ALL

# one condition at a time (run twice, then merge the two results CSVs)
Rscript scripts/scdist_perturbation_distance.R.txt --input-rds CD4T.seu.globalC.rds \
    --subset-col time --subset-value pre  --output-dir out --prefix cd4t_PRE
Rscript scripts/scdist_perturbation_distance.R.txt --input-rds CD4T.seu.globalC.rds \
    --subset-col time --subset-value post --output-dir out --prefix cd4t_POST

Parameters

Flag scDist argument Default Notes
--input-rds – required Seurat .rds
--output-dir – scdist_out output root; creates Img/, Stat/, Rdata/ under it
--prefix – scdist prefix of every output file
--assay – RNA Seurat assay
--slot normalized_counts scale.data slot/layer used as the input matrix
--d d 20 number of PCs
--fixed-effects fixed.effects response comma-separated; first = condition
--random-effects random.effects sample comma-separated; subject/batch
--clusters clusters subCluster1 cell-type column
--min-count-per-cell min.count.per.cell 20 raised to d internally
--truncate truncate FALSE negative distances → 0
--seed – 1 Monte-Carlo p-values are stochastic
--make-plots – TRUE DistPlot + FDRDistPlot (PDF/PNG)
--subset-col / --subset-value – – keep cells where meta[col] %in% value; repeatable, pairs ANDed, comma-separated values ORed

Rscript scripts/scdist_perturbation_distance.R.txt --help prints the full usage.

Outputs

In-memory object returned by scDist() (verified against a real run's .rds):

out$results     data.frame, rownames = cell-type labels, columns:
                  &quot;Dist.&quot;          posterior median distance (NOT D.hat)
                  &quot;95% CI (low)&quot;   posterior 2.5% quantile
                  &quot;95% CI (upper)&quot; posterior 97.5% quantile
                  &quot;p.val&quot;          Monte-Carlo p-value (resolution ~1e-5)
                cell types that were skipped are ABSENT from this table
out$vals[[ct]]  per cell type: D.hat, D.se, W, beta (per PC), beta_sd, lambda,
                scores, data, dfs, p.sum, p.max, D.post.med, D.post.lb,
                D.post.ub, loadings, beta.hat
out$design      the fitted formula, e.g. y ~ response + (1 | sample)
out$gene.names  genes used (== nrow of the input matrix)

Files written by the script — --output-dir is the output root; every file
keeps its name and lands in one of three fixed sub-directories, and the script
prints a content summary of the three directories at the end:

  • &lt;out&gt;/Rdata/&lt;prefix&gt;.rds — the full scDist object (feeds DistPlot / distGenes / plotBetas later)
  • &lt;out&gt;/Stat/&lt;prefix&gt;.results.csv — cell_type, Dist., 95% CI (low), 95% CI (upper), p.val, FDR
    (FDR added by the script with p.adjust(method=&quot;fdr&quot;); p.val is the raw value)
  • &lt;out&gt;/Stat/&lt;prefix&gt;.vals_summary.csv — per cell type n_cells, D.hat, D.se, W, p.sum, p.max, D.post.med/lb/ub
  • &lt;out&gt;/Img/&lt;prefix&gt;.DistPlot.{pdf,png}, &lt;out&gt;/Img/&lt;prefix&gt;.FDRDistPlot.{pdf,png} — --make-plots TRUE
  • &lt;out&gt;/Stat/&lt;prefix&gt;.log.txt — parameters, design echo, warnings, saved paths

Layout in short: Img/ = figures, Stat/ = tables + log, Rdata/ = saved objects.

Reading the numbers: larger Dist. = the cell type's transcriptome shifted
further between the two conditions. Distances are in the units of the PCA score
space of that cell type, so compare cell types within one run, not across runs
(different gene sets / cell counts give different scales). Dist. = 0 with a
non-significant p-value = "no evidence of a shift", not "cells are identical".

Pitfalls

  • Use scale.data, not counts. scDist runs PCA and then lmer on the values.
    Raw counts make the distance dominated by library size / mean expression and
    break the Gaussian mixed-model assumptions. The original script's
    srt@assays[[&quot;RNA&quot;]]@scale.data is exactly right; on Seurat v5 use
    GetAssayData(srt, assay = &quot;RNA&quot;, layer = &quot;scale.data&quot;) (passing slot= is
    defunct in SeuratObject 5). scale.data only exists after ScaleData(); if it
    was run on variable features only, out$gene.names is just those genes (1500 in
    the original CD4T object). Multi-layer (v5) objects may need JoinLayers()
    first, otherwise the layer is empty — the script detects an empty slot and stops
    with that hint.
  • d vs cell-type size. d (default 20) is the number of PCs. scDist raises
    min.count.per.cell to at least d and then nexts over any cell type with
    fewer cells, silently dropping it from out$results. With small
    sub-clusters you must lower d (e.g. 5–10) or the cell type simply will not
    appear. Always diff names(out$vals)/rownames(out$results) against
    unique(meta[[clusters]]) to see which cell types were skipped (the script
    warns up front and reports the design). Too-large d also over-fits well before
    it errors (inferred from the source, not documented upstream).
  • random.effects must be able to absorb the individual differences — that is
    the whole point of the method. Pass the subject/patient/sample column, not the
    condition. If the same subjects are not present in both conditions (or, worse,
    every subject is single-condition), condition and subject are confounded and the
    distance measures subject identity. Check table(condition, subject) before
    running; the script warns when a subject appears in only one condition.
  • Never put clusters into random.effects and never put the condition into
    random.effects: the condition must stay a fixed effect (fixed.effects[1]),
    otherwise the whole estimated distance is absorbed by the random structure.
  • Run one cell type per call — you already do. clusters is a column, not a
    value: scDist loops internally. Do not pre-subset the object to one cell
    type (--subset-* is for conditions/timepoints, not for cell types).
  • Set a seed. p-values come from a 10^5-replicate Monte-Carlo loop (and ashr
    posterior sampling), so re-running an unchanged analysis can move the smallest
    p-values slightly; --seed (default 1) makes runs reproducible.
  • A cell type is skipped, not analysed, when any fixed/random effect has a single
    level inside it
    (check_effects()), e.g. a sub-cluster present in only one
    of the two conditions. The script warns about this too.
  • Per cell type, one lmer per PC: with many cell types and many cells the run
    is the expensive part (each fit is a mixed model). Pre-filtering genes to HVGs
    (as the original object was: 1500 genes) keeps it fast.
  • Direction is not reported. scDist gives a magnitude; use
    distGenes(out, cluster=...) / featureImportance / plotBetas to see
    which genes moved and in which direction. For "up vs down" claims, follow up
    with a pseudobulk DE.
  • DistPlot/FDRDistPlot need ggplot2 ≥ 3.x and ggpubr; distGenes needs
    ggrepel. Plotting failures must not lose the results — the script writes the
    CSV/RDS first and treats plot errors as warnings.
  • fixed.effects order is load-bearing: only fixed.effects[1] is tested
    (design.null &lt;- makeDesign(fixed.effects[-1], ...)); anything after it is a
    covariate. Passing &quot;age,response&quot; computes the age effect while looking like a
    response analysis.

Environment

  • R ≥ 4.0 (package requirement; verified on R 4.5.3 in this container).
  • Packages: scDist (GitHub only — not on CRAN/Bioconductor), Seurat /
    SeuratObject, plus scDist's own imports: lmerTest, lme4, irlba, ashr,
    data.table, ggplot2, ggpubr, ggrepel (≥0.9.6), ggraph.
    sscVis is only used in the original script for a colour palette
    (sscVis:::auto.colSet(16, name=&quot;Paird&quot;)) — cosmetic, not required for the
    analysis.
  • Install: Rscript -e &#x27;devtools::install_github(&quot;phillipnicol/scDist&quot;)&#x27;
    (or remotes::install_github). No CRAN/Bioconductor equivalent exists.
  • The bundled script uses base-R argument parsing only — it has no
    optparse/argparse dependency, so --help works even before scDist is
    installed.
  • Status in this container (checked 2026-09, R 4.5.3): installed — Seurat 5.5.1,
    lme4 2.0.6, irlba 2.3.7, data.table 1.18.4, ggplot2 4.0.3, ggpubr 0.6.3,
    ggrepel 0.9.8, ggraph 2.2.2, dplyr 1.1.4, tibble 3.3.1;
    not installed — scDist, lmerTest, ashr (install scDist and let its
    dependencies resolve lmerTest/ashr).

> Packaging note. Scripts and tables in this skill carry a .txt suffix on their
> original extension (e.g. .R.txt, .tsv.txt) because the SkillHub upload allowlist
> does not accept .R or .tsv. This is cosmetic: Rscript is extension-agnostic, so
> Rscript scripts/&lt;name&gt;.R.txt ... behaves exactly like .R, and tab-separated data
> parses identically from .tsv.txt. Keep the suffix when repackaging.

常见问题

5 问
答案由本站依据条目字段整理
scDist 扰动距离怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_7ece4fea/scdist-perturbation-distance。安装方式为未标注。装完刷新技能列表或重开客户端。

scDist 扰动距离支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

scDist 扰动距离权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

scDist 扰动距离收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

scDist 扰动距离用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。