Spaces:
Running
Running
S0-R1-C5.5-R3 Typed Causal Actor Frame Closure
#86
by GuXiaopeng - opened
- core/quantitative_engine.py +91 -45
core/quantitative_engine.py
CHANGED
|
@@ -878,53 +878,76 @@ Keywords: {keywords}"""
|
|
| 878 |
r"causation|cause(?:s|d|ing)?)"
|
| 879 |
)
|
| 880 |
direct_patterns = (
|
| 881 |
-
r"\b(?:causes?|caused|causing)\b",
|
| 882 |
-
r"\b(?:leads?|led)\s+to\b",
|
| 883 |
-
r"\b(?:drives?|drove|driven)\b",
|
| 884 |
-
r"\b(?:determines?|determined)\b",
|
| 885 |
-
r"\b(?:produces?|produced)\b",
|
| 886 |
-
r"\b(?:results?|resulted)\s+in\b",
|
| 887 |
-
r"\b(?:
|
| 888 |
-
r"\
|
| 889 |
-
r"\b(?:
|
|
|
|
|
|
|
| 890 |
)
|
| 891 |
|
| 892 |
-
def
|
| 893 |
-
"""Return
|
| 894 |
-
|
| 895 |
-
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
a statistical-artifact target immediately after it. Merely seeing
|
| 901 |
-
``analysis`` or ``model`` is not enough; e.g. ``the analysis produced
|
| 902 |
-
higher engagement`` remains fail-closed.
|
| 903 |
"""
|
| 904 |
-
prefix = value[max(0, match.start() -
|
| 905 |
-
|
| 906 |
-
|
| 907 |
-
|
| 908 |
-
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
|
| 912 |
-
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 916 |
r"mediation\s+(?:analysis|model)|"
|
| 917 |
-
r"estimation(?:\s+procedure|
|
| 918 |
-
r"statistical\s+(?:analysis|model|procedure|method)|"
|
| 919 |
-
r"
|
| 920 |
-
r"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 921 |
)
|
| 922 |
-
if
|
| 923 |
-
return
|
| 924 |
-
|
| 925 |
-
|
| 926 |
-
|
| 927 |
-
|
|
|
|
|
|
|
| 928 |
target_pattern = (
|
| 929 |
r"^\s*(?:(?:an?|the|this|that|these|those|following|reported|"
|
| 930 |
r"standardized|standardised|numerical|estimated|95\s*percent|95%)\s+){0,6}"
|
|
@@ -935,10 +958,33 @@ Keywords: {keywords}"""
|
|
| 935 |
r"correlations?|covariances?|variances?|loadings?|"
|
| 936 |
r"test\s+statistics?|p[- ]?values?|vif(?:s|\s+values)?|"
|
| 937 |
r"cronbach(?:'s)?\s+alpha|composite\s+reliability|"
|
| 938 |
-
r"average\s+variance\s+extracted|ave|numerical\s+estimates?|estimates?
|
|
|
|
|
|
|
|
|
|
| 939 |
)
|
| 940 |
return bool(re.search(target_pattern, suffix, flags=re.I))
|
| 941 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 942 |
def direct_match_is_disclaimed(match):
|
| 943 |
prefix = value[max(0, match.start() - 220):match.start()]
|
| 944 |
if re.search(
|
|
@@ -974,12 +1020,12 @@ Keywords: {keywords}"""
|
|
| 974 |
return False
|
| 975 |
|
| 976 |
saw_disclaimed_direct = False
|
| 977 |
-
for pattern in direct_patterns:
|
| 978 |
for match in re.finditer(pattern, value, flags=re.I):
|
| 979 |
if direct_match_is_disclaimed(match):
|
| 980 |
saw_disclaimed_direct = True
|
| 981 |
continue
|
| 982 |
-
if
|
| 983 |
continue
|
| 984 |
return "AFFIRMATIVE_CAUSAL"
|
| 985 |
|
|
|
|
| 878 |
r"causation|cause(?:s|d|ing)?)"
|
| 879 |
)
|
| 880 |
direct_patterns = (
|
| 881 |
+
(r"\b(?:causes?|caused|causing)\b", "STRONG"),
|
| 882 |
+
(r"\b(?:leads?|led)\s+to\b", "STRONG"),
|
| 883 |
+
(r"\b(?:drives?|drove|driven)\b", "STRONG"),
|
| 884 |
+
(r"\b(?:determines?|determined)\b", "STRONG"),
|
| 885 |
+
(r"\b(?:produces?|produced)\b", "AMBIGUOUS_REPORTING"),
|
| 886 |
+
(r"\b(?:results?|resulted)\s+in\b", "AMBIGUOUS_REPORTING"),
|
| 887 |
+
(r"\b(?:yields?|yielded)\b", "AMBIGUOUS_REPORTING"),
|
| 888 |
+
(r"\b(?:generates?|generated)\b", "AMBIGUOUS_REPORTING"),
|
| 889 |
+
(r"\b(?:transmits?|transmitted)\s+(?:an?\s+|the\s+)?causal\s+effect\b", "STRONG"),
|
| 890 |
+
(r"\bcausally\s+(?:transmits?|mediates?|affects?|influences?)\b", "STRONG"),
|
| 891 |
+
(r"\b(?:has|have|had|exerts?|exerted)\s+(?:an?\s+|the\s+)?causal\s+effect\b", "STRONG"),
|
| 892 |
)
|
| 893 |
|
| 894 |
+
def local_actor_text(match):
|
| 895 |
+
"""Return the grammatical actor window immediately before a predicate.
|
| 896 |
+
|
| 897 |
+
R3 deliberately classifies the *actor* rather than maintaining an
|
| 898 |
+
ever-growing whitelist of reporting artefacts. Leading adverbial or
|
| 899 |
+
prepositional phrases (``In the analysis, ...`` / ``Using Spearman
|
| 900 |
+
correlations, ...``) are peeled away so that a nearby mention of an
|
| 901 |
+
analysis cannot shield a later construct-level causal assertion.
|
|
|
|
|
|
|
|
|
|
| 902 |
"""
|
| 903 |
+
prefix = value[max(0, match.start() - 260):match.start()]
|
| 904 |
+
actor = re.split(r"[.;!?]", prefix)[-1].strip()
|
| 905 |
+
lead = re.match(
|
| 906 |
+
r"^(?:in|using|with|based\s+on|according\s+to|after|before|when|while|because|"
|
| 907 |
+
r"although|though|given|under|for|as)\b[^,]{0,180},\s*(.+)$",
|
| 908 |
+
actor,
|
| 909 |
+
flags=re.I,
|
| 910 |
+
)
|
| 911 |
+
if lead:
|
| 912 |
+
actor = lead.group(1).strip()
|
| 913 |
+
return actor[-220:]
|
| 914 |
+
|
| 915 |
+
def actor_type(match):
|
| 916 |
+
"""Classify the predicate subject as analytical, weak-analytical, or other.
|
| 917 |
+
|
| 918 |
+
``ANALYTICAL_ACTOR`` is intentionally restricted to explicit
|
| 919 |
+
statistical/diagnostic actors. Generic ``model``/``procedure`` terms
|
| 920 |
+
are weak because they can also denote the substantive AI system or an
|
| 921 |
+
intervention; they are exempt only when the predicate target is a
|
| 922 |
+
recognisable reporting artefact.
|
| 923 |
+
"""
|
| 924 |
+
actor = local_actor_text(match)
|
| 925 |
+
strong_actor = (
|
| 926 |
+
r"\b(?:analysis|analyses|"
|
| 927 |
+
r"bootstrap(?:\s+(?:resampling|procedure|computation|analysis))?|"
|
| 928 |
+
r"resampling(?:\s+(?:procedure|analysis|computation))?|"
|
| 929 |
+
r"regression\s+(?:analysis|model)|association\s+(?:analysis|model)|"
|
| 930 |
r"mediation\s+(?:analysis|model)|"
|
| 931 |
+
r"estimation(?:\s+(?:procedure|method|analysis))?|estimator|"
|
| 932 |
+
r"statistical\s+(?:analysis|model|procedure|method|test)|"
|
| 933 |
+
r"robustness\s+(?:check|test|analysis)|"
|
| 934 |
+
r"sensitivity\s+(?:check|test|analysis)|"
|
| 935 |
+
r"diagnostic\s+(?:check|test|analysis)|"
|
| 936 |
+
r"rank[- ]order\s+(?:robustness\s+)?check|"
|
| 937 |
+
r"(?:spearman|pearson|rank[- ]order)\s+correlations?|"
|
| 938 |
+
r"correlation\s+(?:analysis|matrix|check|test)|"
|
| 939 |
+
r"hypothesis\s+test|significance\s+test|"
|
| 940 |
+
r"variance\s+inflation\s+factor(?:\s+check)?|vif(?:\s+check)?|"
|
| 941 |
+
r"measurement\s+assessment|descriptive\s+analysis)\b"
|
| 942 |
)
|
| 943 |
+
if re.search(strong_actor, actor, flags=re.I):
|
| 944 |
+
return "ANALYTICAL_ACTOR"
|
| 945 |
+
if re.search(r"\b(?:model|procedure|method|computation|calculation)\b", actor, flags=re.I):
|
| 946 |
+
return "WEAK_ANALYTICAL_ACTOR"
|
| 947 |
+
return "OTHER_ACTOR"
|
| 948 |
+
|
| 949 |
+
def predicate_target_is_reporting_output(match):
|
| 950 |
+
suffix = value[match.end():min(len(value), match.end() + 220)]
|
| 951 |
target_pattern = (
|
| 952 |
r"^\s*(?:(?:an?|the|this|that|these|those|following|reported|"
|
| 953 |
r"standardized|standardised|numerical|estimated|95\s*percent|95%)\s+){0,6}"
|
|
|
|
| 958 |
r"correlations?|covariances?|variances?|loadings?|"
|
| 959 |
r"test\s+statistics?|p[- ]?values?|vif(?:s|\s+values)?|"
|
| 960 |
r"cronbach(?:'s)?\s+alpha|composite\s+reliability|"
|
| 961 |
+
r"average\s+variance\s+extracted|ave|numerical\s+estimates?|estimates?|"
|
| 962 |
+
r"(?:a\s+)?pattern(?:\s+of\s+(?:associations|correlations|estimates))?|"
|
| 963 |
+
r"(?:a\s+)?(?:similar|consistent|comparable)\s+pattern|"
|
| 964 |
+
r"findings?|results?)\b"
|
| 965 |
)
|
| 966 |
return bool(re.search(target_pattern, suffix, flags=re.I))
|
| 967 |
|
| 968 |
+
def direct_match_is_analytical_reporting(match, predicate_kind):
|
| 969 |
+
actor = actor_type(match)
|
| 970 |
+
if predicate_kind == "AMBIGUOUS_REPORTING":
|
| 971 |
+
# ``analysis/check/test produced/resulted/yielded/generated ...``
|
| 972 |
+
# describes what an analytical operation reported. It is not a
|
| 973 |
+
# study-construct causal assertion even when the following prose is
|
| 974 |
+
# stylistically loose (e.g. ``the analysis produced higher
|
| 975 |
+
# engagement``). The CAR layer may flag wording separately; this
|
| 976 |
+
# causal gate must not terminate the manuscript for it.
|
| 977 |
+
if actor == "ANALYTICAL_ACTOR":
|
| 978 |
+
return True
|
| 979 |
+
if actor == "WEAK_ANALYTICAL_ACTOR" and predicate_target_is_reporting_output(match):
|
| 980 |
+
return True
|
| 981 |
+
return False
|
| 982 |
+
|
| 983 |
+
# Strong causal predicates remain fail-closed. Preserve only the
|
| 984 |
+
# narrow statistical-reporting idiom already accepted by R1, such as
|
| 985 |
+
# ``the analysis led to the following numerical estimate``.
|
| 986 |
+
return actor in {"ANALYTICAL_ACTOR", "WEAK_ANALYTICAL_ACTOR"} and predicate_target_is_reporting_output(match)
|
| 987 |
+
|
| 988 |
def direct_match_is_disclaimed(match):
|
| 989 |
prefix = value[max(0, match.start() - 220):match.start()]
|
| 990 |
if re.search(
|
|
|
|
| 1020 |
return False
|
| 1021 |
|
| 1022 |
saw_disclaimed_direct = False
|
| 1023 |
+
for pattern, predicate_kind in direct_patterns:
|
| 1024 |
for match in re.finditer(pattern, value, flags=re.I):
|
| 1025 |
if direct_match_is_disclaimed(match):
|
| 1026 |
saw_disclaimed_direct = True
|
| 1027 |
continue
|
| 1028 |
+
if direct_match_is_analytical_reporting(match, predicate_kind):
|
| 1029 |
continue
|
| 1030 |
return "AFFIRMATIVE_CAUSAL"
|
| 1031 |
|