Each condition is fitted by the engines on its own complete pairs, but the
outcome bounds NSCA measured the admissible region against were taken from
every observed outcome. A row with an outcome and no condition value therefore
widened the box on one side of the identity and not on the other. On one such
dataset admissible_region_share fell from 0.167 to 0.056, the area identity
missed by 0.11, and geometry_acceptable -- and with it joint_support --
turned FALSE. With two conditions the effect is not confined to edge cases:
missing values in one condition stretched its bounds to the outcome range of
the other, and the identity missed by 0.65. Outcome bounds are now taken per condition, from the
same pairs and the same scope segment the engines use. Complete data is
unaffected.
relevance given as a named character vector, such as
c(necessity = "0.1", sufficiency = "0.2"), stayed character, and the
support rule then compared effect sizes with thresholds as strings. Named
input is now reordered after it has been converted to numbers.shared.seed restored the caller's random stream only when one already
existed. In a fresh session it left behind the stream it had created, so every
later draw followed from that seed. It now removes it, as documented.nsca_extract() said every retired name had been renamed in 0.3.0; five of
them were renamed in 0.4.0. The warning now names the right release.nsca_extract() refuses a frontier that was not estimated on every route.
The nec: and suf: routes used to return NA for it, which looks like a
missing measurement; the joint route now gives the same "was not estimated"
message as nsca_thresholds() and nsca_plot().CRAN review asked that \dontrun{} be kept for code that genuinely cannot
run. The one example that used it, nsca_extract(), relied on a fit it never
created; it now builds its own model and runs unwrapped.
nsca(), nsca_table(), nsca_results() with its print() and summary()
methods, nsca_thresholds() and nsca_plot() with its plot() method had no
examples and now have runnable ones. The nsca() example keeps the default
1000 permutations, which take longer than CRAN's five-second budget, so it is
wrapped in \donttest{}: it still runs under example() and under
R CMD check --as-cran.
nsca_reference()'s example and its list of returned columns had been added
to the .Rd file by hand and were missing from the roxygen source, so the next
roxygen2::roxygenise() would have dropped them. They are now in the source,
and every help page is regenerated from it.
?nsca_table still used the name retired in 0.4.0,
data_zone_share; it now reads admissible_region_share.legacy in nsca_table() and nsca_thresholds() was documented as
appending the names of one release each; both append those of 0.3.0 and
0.4.0.NSCA_0.4.3.tar.gz and described SCAtools as a
source-only package. SCAtools is on CRAN, so installation is now
install.packages("NSCA"), with the source-tarball route kept below it.URL, BugReports and both READMEs pointed at
youngchanresearcher/NSCA_condition_analysis. They now point at the package's
repository, https://github.com/youngchanresearcher/NSCA. Nothing else changed;
the entry for 0.4.3 below had been relabelled 0.4.4 in that release and is
restored to its own version here.
Authors@R named a placeholder, NSCA Contributors <maintainer@example.org>,
which CRAN rejects: the maintainer must be a real person at a working address.
Both are now Young Chan youngchanresearcher@gmail.com.
The package had no inst/CITATION, so citation("NSCA") fell back to the
entry R generates from DESCRIPTION. That entry was correct but silent about
where the numbers come from. A CITATION file now names NSCA, SCAtools and the
NCA method article together, and reads the version from DESCRIPTION.
region was retired but never reachable0.3.0 renamed the threshold-table column region to threshold_status, and
that rename is printed in the table below, in both READMEs and in the package
guide. The entry was never added to the legacy map, so nsca_legacy_names()
omitted it, nsca_thresholds(legacy = TRUE) did not append a region column,
and nsca_extract("region") reported it as an unknown parameter rather than a
retired name — the one thing the retirement policy promises. It is now in the
map, and the test pins the whole documented mapping rather than a sample of it,
so a missing entry cannot pass again.
Both READMEs gained the installation section they never had. NSCA needs NCA and SCAtools in place first, and the order matters, which is worth stating where a reader starts.
DESCRIPTION gained URL and BugReports, and both READMEs now link the
repository. SCAtools is released separately, so its own link is given too:
URL: https://github.com/youngchanresearcher/NSCA_condition_analysis
BugReports: https://github.com/youngchanresearcher/NSCA_condition_analysis/issues
scale (breaking)nsca_thresholds() reported necessity_threshold and sufficiency_threshold
on the requested scale, but necessity_sufficiency_interval and
overlap_width were left in actual units on every scale. The three columns
print side by side, so a reader who subtracted the two thresholds did not get
the interval: on the default "percentage.range" the two thresholds were
percentages of the range and the width between them was in the units of X.
The behaviour was documented -- the help page said the interval is "expressed
in the units of X" and told the reader to normalise -- but the normalised
number was the one the package would not produce, and nothing in the table
said the row mixed two kinds of column.
Both columns are now reported on scale, so a row can be checked by
subtraction. necessity_sufficiency_interval_actual and overlap_width_actual
are new and hold the previous values, whatever scale is asked for; the signed
threshold_gap_actual is unchanged.
Only the reported magnitude moved. The sign is still settled in actual units
and carried over, because under convention = "directional" a low-X direction
is mirrored: taking the sign from the reported difference would swap
"admissible interval" and "frontiers overlap" in exactly the views where
the mirroring applies. threshold_status, thresholds_compatible and every
component and joint index are untouched.
Under scale = "percentile" the column is a difference of ranks, so it reads
as the share of cases between the two thresholds rather than as a width. The
help page now says so, and points at "percentage.range" or "sd" for a
normalised width.
To restore the old numbers, read the _actual columns or ask for
scale = "actual".
Three fixes found by the first full R CMD check --as-cran of the 0.4.x line.
All three predate 0.4.1. No code, argument, column, default or reported
quantity changed.
nsca_table() documentation was malformed (WARNING)checkRd refused nsca_table.Rd: \emph is not valid inside \code. The
formula for balanced_joint_effect had been written to the .Rd as
\code{2 \emph{ sqrt(d_nec } d_suf)} -- a markdown converter had read the two
multiplication signs in 2 * sqrt(d_nec * d_suf) as emphasis markers and
turned the text between them into \emph. The .Rd now carries the formula
it was meant to carry. The roxygen source was already correct, so nothing in
R/results.R needed changing.
test-invariants.R passed info = name to expect_gte() and expect_lte().
The ordered comparisons take label and expected.label, not info, so
current testthat raises "unused argument" -- which aborts the whole
test_that() block rather than failing one expectation. This is why the suite
reported 1 error against 1032 passes: the assertion itself was fine and had
never actually run. Both calls now pass label.
The neighbouring expect_true(..., info = ...) calls are correct and are left
alone; expect_true() does take info.
README_zh-TW.md moves into inst/docs/ (NOTE)R CMD check counts any unrecognised top-level file as a NOTE. From inst/
the translation is still shipped and is now reachable from R:
file.show(system.file("docs", "README_zh-TW.md", package = "NSCA")).
The "unable to verify current time" NOTE is R CMD check failing to reach a
time server. It says nothing about the package and no package change can
remove it. Set _R_CHECK_SYSTEM_CLOCK_ = 0 before checking to skip it.
biconditional stays a column nameThe article calls the joint claim necessary-and-sufficient, and uses "biconditional" only in contrast: section 2.1 says each component claim "is a conditional, not a biconditional". Using the same word for the joint claim therefore reads against the article it follows. All prose now says necessary-and-sufficient -- the DESCRIPTION, the roxygen documentation, the code comments, the printed inference notes, and both READMEs.
Nothing was renamed. The biconditional column of nsca_direction_map() keeps
its name: it holds the joint statement written out, and the short logical word
is the more usable column name. necessary_and_sufficient_statement would be
three times as long for the same content, in a data frame whose other columns
are one or two words. Every field name, list element and status value is
unchanged, including the necessary_and_sufficient element of
nsca_results().
"ols" is an ordinary least-squares regression of the outcome on the
condition, fitted to all the data. It has always been refused as a component,
and still is: it summarises central tendency, not an empty space, so it can be
neither the necessity nor the sufficiency side. Since 0.4.1 it can be drawn
alongside them. Section 6.1 of the framework keeps average-effect and condition
analysis side by side rather than merging them into one number, and cites the
combined importance-performance map as the precedent for showing two logics on
one picture without collapsing them.
nsca_analysis() and nsca() gain reference. reference = "ols" draws
the regression line on nsca_plot() as a dotted grey line, outside the
component legend, with the caption saying what it is.ceilings still refuses "ols"; the warning now says where the line
belongs.nsca_reference() reports its intercept, slope, R-squared and the
observations it was fitted to. It is available whether or not the line was
drawn.nsca_terms() gains a central tendency row.nsca_table() for that reason.Requires SCAtools >= 0.4.1.
This release adopts the vocabulary of condition analysis in degree, the framework that places SCA and NSCA beside NCA. Terminology follows the article; the package's own names survive only where the article has nothing to say. Nothing was removed: every retired name still works.
The framework names the two quantities 0.3.0 had called the data zone.
data_zone_share becomes admissible_region_share.data_zone_width
becomes necessity_sufficiency_interval.Two threshold_status values change with them: "determinate" becomes
"exact correspondence", the limiting case in which one X value is both the
minimum required and the sufficient level, and "data zone" becomes
"admissible interval".
The documentation now states three things the framework is careful about and 0.3.0 was not. The interval is expressed in the units of X, so it is scale-dependent and comparable across studies only after normalisation. It is not a confidence interval and carries no statistical uncertainty. And an estimated interval of zero is consistent with exact correspondence but does not by itself establish it; a small non-zero interval should be called near correspondence only when a substantively justified tolerance has been defined.
Evidence for both components is joint support, which is a claim about the content of the joint hypothesis rather than a demand that the components have identical effects or thresholds.
nsca_supported becomes joint_support.conjunction becomes joint_support_status.Section 5.2 of the framework states a consistency check the package did not implement. Whenever the two frontiers do not cross, the floor lies at or below the ceiling throughout the scope, so no point belongs to both expected empty spaces; because each component effect size is that space's share of the same scope, the two shares cannot sum to more than one. Component effect sizes summing above one therefore say the frontiers have crossed and the result needs diagnosis, not that it is unusually strong.
component_sum reports d_nec + d_suf, so the framework's own rule can be
applied directly by any reader.frontiers_crossed answers the same question from the measurement rather
than from the sum.The sum is a proxy for a crossing that is not otherwise available. Here it is
available: overlap_share is the area on which the two empty spaces actually
overlap, integrated from the reconstructed frontiers. Deciding from the
measurement avoids the proxy's failure mode, which is that the sum comes from
the engines and the comparison threshold from the geometry, so the two can
disagree in the last few digits on exactly the configuration the check exists
to bless.
That configuration is the perfect diagonal. A step frontier overlaps itself by
construction: between two consecutive observations the upper staircase still
holds the earlier value while the lower one has already moved, so the two
spaces overlap on every tread, exactly 1 / (n - 1) of the scope summed over
the n - 1 treads, and a perfect diagonal attains it. That allowance is
subtracted before the comparison. For every smooth frontier the allowance is
zero and any overlap at all is a genuine crossing.
frontiers_crossed asks whether the frontiers crossed at all;
geometry_acceptable asks whether they crossed by more than
geometry.max_overlap. A row can be flagged as crossed and still have
acceptable geometry, which is the useful distinction: one says something
happened, the other says whether it matters.
The framework distinguishes a boundary, the theoretical line separating an
expected empty space from the compatible region, from a frontier, that
boundary estimated from data, and names the direction in which Y is bounded a
ceiling or a floor. The package estimated the right things but never
said which was which, because the argument is called ceilings in every
direction.
nsca_table(), nsca_results(), nsca_corners() and nsca_direction_map()
now report, in the wording of Table 1:
relationship -- the direction as a claim about the theorised X-Y
relationship, with the user's own variable names, for example
"Higher training for higher score". This is a claim about the relationship,
not about the shape of the estimated frontier, which may be a step function
or a straight line under any of the four types.necessity_empty_space and sufficiency_empty_space -- what each expected
empty space would contain.necessity_boundary and sufficiency_boundary -- "ceiling" or "floor".
The two are always one of each, because the corners are diagonally opposite.nsca_thresholds() gains relationship and records the inequality it used.
nsca_thresholds() renames its boundary argument to inequality, matching
SCAtools 0.4.0. A boundary is the theoretical line an empty space is separated
by; it has nothing to do with whether a reported rule uses > or >=. The old
argument still works and warns.
nsca_legacy_names() now covers the 0.4.0 retirements as well as the 0.3.0
ones.nsca_thresholds() gains legacy = TRUE, which nsca_table() already had.
Each table appends only the retired names whose replacement it carries.nsca_extract() asked for a dual-threshold column now explains that such a
column is defined per outcome level and points at nsca_thresholds(),
instead of reporting a name it knows about as unknown.nsca_terms() is a new machine-readable glossary linking each term of the
framework to the name this package uses for it.sufficiency_threshold columns this
release reads. The two packages now use one name for one quantity.This release adopts the unified conceptual specification: the reported quantities now follow one geometric identity instead of being defined separately, the vocabulary names the geometry rather than an interpretation, and a statistic of both components can be tested properly for the first time.
The two empty zones and the region between them tile the analytic scope, so by inclusion and exclusion
data_zone_share = 1 - d_nec - d_suf + overlap_share
Every other area quantity is derived from this rather than asserted. Two consequences are new:
data_zone_share >= 0 gives
d_nec + d_suf <= 1 + O, hence weakest_effect <= 0.5 + O/2 and
balanced_joint_effect <= 1 + O. Both are attained exactly by a perfect
diagonal, where O is 1/(n - 1): at n = 40 the observed values are 0.5128
and 1.0256 against bounds of 0.5128 and 1.0256. Earlier versions could only
say the excess was "of order 1/n"; it is now an equality, so a reader can
subtract the discretization instead of allowing for it.data_zone_share is a
share of the scope, so it and joint_empty_zone_coverage always lie in
[0, 1]; the other two indices are bounded only up to the overlap. That is a
technical reason to report the coverage next to them, additional to its
answering a different question.reconstruction_errorThe identity has two computational routes. data_zone_share and
overlap_share are integrated from the frontiers this package reconstructs;
d_nec and d_suf are reported by the engines from their own internal
frontiers. The residual between the routes is now reported per row.
It is the only available check that the reconstruction still matches what the engine actually fitted, and it catches the one failure mode a plot cannot: a wrongly rebuilt frontier still looks like a frontier and still yields plausible areas. Only the identity refuses to close. This was previously asserted on fixtures in the test suite; it now runs on the user's own data.
Old names remain reachable: nsca_table(legacy = TRUE) appends them as
duplicates, nsca_extract() accepts them with a warning, and
nsca_legacy_names() returns the mapping.
| retired | current |
|---|---|
| d_nsca | weakest_effect |
| j_nsca | balanced_joint_effect |
| determinacy | joint_empty_zone_coverage |
| undetermined_share | data_zone_share |
| weaker_side | weaker_component |
| p_nsca | p_nsca_iut |
| undetermined_width (thresholds) | data_zone_width |
| region (thresholds) | threshold_status |
determinacy had to go: it named an interpretation the number does not earn,
since a constant outcome scores 1 on it. The region between the frontiers is
the data zone — the region observations are still admitted in, which is
not the claim that any were observed there, and the documentation now says so
explicitly. The threshold_status value "undetermined" is correspondingly
now "data zone".
p_weakest_perm and the shared permutation sequenceshared.test.rep replaces the engines' two separate permutation runs with one
sequence driving both. Each replication shuffles the outcome once, refits both
engines on that same shuffled frame, and records d_nec, d_suf and their
minimum together.
This is what makes a p-value for min(d_nec, d_suf) meaningful. An
intersection-union rule combines two p-values and needs no assumption about how
they co-vary, but the minimum is a statistic of both components and its null
distribution depends on exactly that co-variation. Two independent permutation
runs would discard the constraint that the two empty zones are disjoint subsets
of one scope, and produce a null distribution no dataset could have generated.
When the shared sequence is used, p_nec and p_suf come from it too, so all
four p-values are mutually consistent; p_source reports which regime produced
them. The p-values carry the Phipson-Smyth correction, so none can be zero.
p_weakest_perm does not replace p_nsca_iut, and the documentation now
gives the sharp reason rather than the vague one. Its null is random pairing
alone, which is a proper subset of the union null "not necessary or not
sufficient": that union contains states, such as necessary-but-not-sufficient,
which are not random pairing at all. Calibrating against random pairing
therefore carries no level-alpha guarantee over the union. It is a sensitivity
analysis; the intersection-union rule remains the decision.
necessity_supported, sufficiency_supported, geometry_acceptable and
nsca_supported are reported separately, so a failure says which of the three
requirements failed rather than collapsing into one boolean.
relevance takes pre-specified practical-relevance thresholds for the
component effect sizes. Support then needs an effect at least that large as
well as a significant test. Without it, support rests on significance alone
and print() says so rather than letting the reader assume otherwise.geometry_acceptable requires a non-degenerate axis, a small
reconstruction_error, and frontier overlap no larger than the 1/(n - 1)
a step frontier produces by construction. A degenerate row can therefore
never be reported as supported.balancebalanced_joint_effect penalises asymmetry but does not measure it: (0.50,
0.125) and (0.25, 0.25) both score 0.50. balance is the geometric mean
over the arithmetic mean, which is 1 exactly when the two components are equal.
The name of the index promised something only this column delivers.
Earlier versions carried hand-written .Rd files alongside roxygen comments.
Running devtools::document() silently replaced the .Rd files with roxygen
output and lost their content, and without Roxygen: list(markdown = TRUE) the
result rendered literal backticks and [function()] links on every help page.
The roxygen blocks are now the single source, the shipped .Rd files are
generated from them and carry the roxygen2 header, and markdown is enabled.
print() separates description from decision: section 3 reports the three
joint summaries side by side, section 4 the p-values and support flags.nsca_analysis() documentation gains sections on matched estimation,
degenerate scopes and the shared sequence.test-decision.R and test-shared.R are new. The four tests
distinguishing the joint indices by curvature, low-end inflation and the
constant-outcome blind spot are restored.j_nsca = 2 * sqrt(d_nec * d_suf) to nsca_table(), the balanced joint
strength. It penalises asymmetry rather than only tracking the weaker side:
at an equal component sum of 0.80, (0.40, 0.40) gives 0.80 while
(0.70, 0.10) gives 0.529.The doubling is normalisation, not a new assumption. The two empty zones are
disjoint subsets of one scope box, so d_nec + d_suf <= 1, and by AM-GM
sqrt(d_nec * d_suf) <= (d_nec + d_suf)/2 <= 0.5. The index therefore spans
[0, 1] and reaches 1 exactly when both components equal 0.5, which is the
single-line case where the two frontiers coincide and the band closes. It is
left unclamped so that the step frontier's 1/n self-overlap stays visible.
nsca_joint(), which exposes the whole power-mean family that min,
the geometric mean and the sum belong to, at p = -Inf, p = 0 and p = 1.This is a correction to how earlier versions framed the choice. d_nsca was
described as though the minimum were the uniquely correct joint effect size
and the alternatives were mistakes. They are not: they are the same family at
different degrees of compensation, and nothing in the geometry of two empty
zones fixes the degree. The documentation now names the parameter instead of
hiding a choice inside a formula.
The geometric mean is documented as partially compensatory, not as a
non-compensatory logical AND. A larger component does raise j_nsca, at a
diminishing rate. min is the fully non-compensatory end of the family and
the sum the fully compensatory end; j_nsca sits between them, and saying
otherwise would overstate what a geometric mean does.
No magnitude benchmarks are asserted for d_nsca, j_nsca or
determinacy, and the documentation now says why rather than staying silent.
Conventions for a single NCA effect size do not transfer: the scales differ,
and under independence both components carry a positive finite-sample bias
that j_nsca amplifies rather than cancels, by an amount depending on n,
the frontier technique and the scope. Calibration is a simulation question.
Adds a degenerate column and a warning at analysis time for an axis that
does not vary inside the declared scope. This is the blind spot all three
area summaries share: a constant outcome at the centre of an imposed scope
leaves the upper and lower halves both empty, so d_nec = d_suf = 0.5, the
band closes, and every index reports a perfect biconditional for data with no
information in it. j_nsca is the most exposed of the three, since d_nsca
at least follows the weaker side when the constant sits off centre. A second,
milder warning fires when the observations span less than five per cent of
the declared scope on either axis.
The other thing called a horizontal line — a flat frontier over a filled scope — needs no special rule and gets none. There is no empty zone on either side, so every index is correctly zero.
print() and summary() now show all three summaries side by side with a
one-line statement of what each measures, and say that no benchmarks exist.determinacy column to nsca_table(), equal to
1 - undetermined_share: the share of the scope the two claims between them
rule out. It is the complement of the band rather than the raw sum
d_nec + d_suf, which measures the same thing but inherits the step
frontier's own overlap and can exceed 1.It exists because d_nsca and the band answer different questions and
neither dominates the other. d_nsca is depressed by curvature: a perfect
bijection such as Y = X^3 scores 0.25 because the sufficiency zone it
leaves really is small. determinacy is curvature-neutral and reaches 1 for
Y = X and Y = X^3 alike, but it is inflated at the low end, where a loose
scatter already scores about 0.2.
determinacy is not an effect size and the documentation says so. A constant
outcome closes the band completely and scores 1 while satisfying neither
component. The permutation screen is what rules that out, not the index.
nsca_results() and the print/summary methods now expose all three requested
layers explicitly: necessity, sufficiency, and the joint NSCA table.p_nsca = max(p_nec, p_suf) and matching
component/joint significance flags. Documentation now states the correct
scope of this conjunction: the underlying NCA p-values test a
random-pairing/independence null and do not directly prove biconditionality.LH and LL) threshold gaps now use the reversed condition-axis
ordering. Negative gaps are reported as frontier overlap instead of being
silently changed to zero..nsca_band() now returns the documented crossed flag, fixing the package's
own failing geometry test.X2.
The earlier visual test used sort(runif(n)), which made X2 monotonically
related to the already ordered outcome and invalidated the expected wide-band
check.First release.
nsca_analysis() estimates both components of a biconditional statement on
diagonally opposite corners of the same scatter plot: necessity through
NCA, sufficiency through SCAtools.nsca_table() reports both component effect sizes, the descriptive joint index,
the undetermined share of the scope, and an intersection-union verdict.nsca_thresholds() gives dual thresholds and the undetermined region for
every outcome level.nsca_plot() draws both frontiers and shades the undetermined band.nsca_corners() and nsca_direction_map() expose the corner mapping.min(d_nec, d_suf) falls to zero as soon as either component does and stays
on the components' own scale. The undetermined band remains separate because
it answers how much of the scope neither claim rules out.1/n: a perfect diagonal through 40 points
gives 0.513. overlap_share reports the overlap, and the frontier-inversion
warning fires only for smooth frontiers, where an inversion means something.nsca_plot()
draws every requested technique on both sides.HH
gets them on the necessity side, LL on the sufficiency side, LH and HL
on neither. They are also expensive when many observations sit on the
frontier, which is exactly the near-deterministic case NSCA is about. No
NSCA statistic uses them. Set purity = TRUE to compute them anyway.ols is refused. It estimates central tendency, not an empty space, so
it yields no component of either claim.Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.