release(camera-ai): publish 0.4.12 catalog portability fix
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+39
-39
@@ -1,39 +1,39 @@
|
||||
{
|
||||
"schemaVersion": "cw-camera-worker-build-identity-v1",
|
||||
"workerVersion": "0.1.7",
|
||||
"createdUtc": "2026-08-09T23:32:08.208961+00:00",
|
||||
"python": "3.12.13",
|
||||
"sourceRootRelative": "cwai_sources/repository",
|
||||
"sourceSha256": {
|
||||
"MachineLearning/CameraDirector/adjacent_transition.py": "6c1b62c2996960af23d62e9c3acd3114600effda03273b006f7076c467c4bdfa",
|
||||
"MachineLearning/CameraDirector/build_hybrid_preparation_cache.py": "427b3cd8fa6eb444517281ef2e21ebc5d751985f4ad271eee49617fda0fb7b33",
|
||||
"MachineLearning/CameraDirector/camera_kinematics.py": "e94eefcb56c4ebdccbc57ae8d3650109b2c912e3642892ac13add9409db21a7f",
|
||||
"MachineLearning/CameraDirector/camera_runtime_data.py": "8ef2e84a9d79b24c3f3232b1f18da49741988765044dffc6075f6e6dd5ff001d",
|
||||
"MachineLearning/CameraDirector/cw_camera_cli.py": "943870a4cdec7e4b830b9c945d690e700902cf2a37d1e49987bba85bf0b0ea87",
|
||||
"MachineLearning/CameraDirector/cw_camera_runtime.py": "7530d24a65a55c235726676b7991b7a375a2739d8b6257f53cc0340f6cc7de1c",
|
||||
"MachineLearning/CameraDirector/data_driven_cut_planner.py": "36cf86a80577278d2e966cb0ebf7c3110b5b1dda5abd1d8a6b0a76e31d10e32b",
|
||||
"MachineLearning/CameraDirector/generate_hybrid.py": "b7e0053563065ebb6d563e72fa0221d31a9e36c1c94c37992f13974b25bb5dfd",
|
||||
"MachineLearning/CameraDirector/hybrid_candidate_cache.py": "a0a5b6a8f612f18cb2875394f17ed89950e1e62e38c1226457d9e35848f6e380",
|
||||
"MachineLearning/CameraDirector/hybrid_cut_reference.py": "306e650dc193fd0d9c42fd52d3f14eef112d1a0da2a27c13b88256d42d8542aa",
|
||||
"MachineLearning/CameraDirector/hybrid_preparation_cache.py": "e4d062a48cf39e01ea97951d103a37817c860e94f440f49f080c622b4969fb5a",
|
||||
"MachineLearning/CameraDirector/hybrid_single_shot_cache.py": "f540e603b0ccffb86ee003d441c3889c245a208db8fd8b2b966fdacfeea30950",
|
||||
"MachineLearning/CameraDirector/planner.py": "8575788c0ff1e984f8238354dcd6de2dab9f62afeb71fa4b77ebfc7c66400372",
|
||||
"MachineLearning/CameraDirector/shot_features.py": "fd912b00320ea53ca682c010de6ed1102edcd021ceb4822a5785033a500786fe",
|
||||
"MachineLearning/CameraDirector/train.py": "070d1c4159c56a2107ae0d383ab0b716b12c13186d45383e94b83d3ba6305d03",
|
||||
"MachineLearning/CameraDirector/trajectory_quality.py": "20cd2ddc1b2349f8c33f6d1460580f37964a521eaa86ceee5b8ae457512ba49d"
|
||||
},
|
||||
"preparationLogicIdentifier": "1cb808e207d54854267a1020a658812c79e9bad5a5296f78140228b3a15eeb3b",
|
||||
"candidateLogicIdentifier": "8dfa557f33c17f4b59849431523cef3650091dc2db3c6c48074888f1f6aef143",
|
||||
"generationCodeIdentifier": "58a7d5d440e5bea630c060823fea7280d81d533e5c4741259ee974bce27e6eb4",
|
||||
"generationCodeFiles": [
|
||||
"adjacent_transition.py",
|
||||
"camera_kinematics.py",
|
||||
"camera_runtime_data.py",
|
||||
"data_driven_cut_planner.py",
|
||||
"generate_hybrid.py",
|
||||
"hybrid_cut_reference.py",
|
||||
"planner.py",
|
||||
"shot_features.py",
|
||||
"trajectory_quality.py"
|
||||
]
|
||||
}
|
||||
{
|
||||
"schemaVersion": "cw-camera-worker-build-identity-v1",
|
||||
"workerVersion": "0.1.8",
|
||||
"createdUtc": "2026-08-15T15:56:01.810396+00:00",
|
||||
"python": "3.12.13",
|
||||
"sourceRootRelative": "cwai_sources/repository",
|
||||
"sourceSha256": {
|
||||
"MachineLearning/CameraDirector/adjacent_transition.py": "6c1b62c2996960af23d62e9c3acd3114600effda03273b006f7076c467c4bdfa",
|
||||
"MachineLearning/CameraDirector/build_hybrid_preparation_cache.py": "427b3cd8fa6eb444517281ef2e21ebc5d751985f4ad271eee49617fda0fb7b33",
|
||||
"MachineLearning/CameraDirector/camera_kinematics.py": "e94eefcb56c4ebdccbc57ae8d3650109b2c912e3642892ac13add9409db21a7f",
|
||||
"MachineLearning/CameraDirector/camera_runtime_data.py": "8ef2e84a9d79b24c3f3232b1f18da49741988765044dffc6075f6e6dd5ff001d",
|
||||
"MachineLearning/CameraDirector/cw_camera_cli.py": "b523fdf6820b3b203dcdef80877a6ad9576fba41d7285c790c300e1813789012",
|
||||
"MachineLearning/CameraDirector/cw_camera_runtime.py": "5cc252ff45b2a80dffbeea14ad37013ba4a428c4f6fe31a617957eec6c823429",
|
||||
"MachineLearning/CameraDirector/data_driven_cut_planner.py": "36cf86a80577278d2e966cb0ebf7c3110b5b1dda5abd1d8a6b0a76e31d10e32b",
|
||||
"MachineLearning/CameraDirector/generate_hybrid.py": "bd37744b7b6573bf14be4f0ec5202f1465e11bff71ccabec210533e135b546c3",
|
||||
"MachineLearning/CameraDirector/hybrid_candidate_cache.py": "a0a5b6a8f612f18cb2875394f17ed89950e1e62e38c1226457d9e35848f6e380",
|
||||
"MachineLearning/CameraDirector/hybrid_cut_reference.py": "306e650dc193fd0d9c42fd52d3f14eef112d1a0da2a27c13b88256d42d8542aa",
|
||||
"MachineLearning/CameraDirector/hybrid_preparation_cache.py": "e4d062a48cf39e01ea97951d103a37817c860e94f440f49f080c622b4969fb5a",
|
||||
"MachineLearning/CameraDirector/hybrid_single_shot_cache.py": "f540e603b0ccffb86ee003d441c3889c245a208db8fd8b2b966fdacfeea30950",
|
||||
"MachineLearning/CameraDirector/planner.py": "8575788c0ff1e984f8238354dcd6de2dab9f62afeb71fa4b77ebfc7c66400372",
|
||||
"MachineLearning/CameraDirector/shot_features.py": "fd912b00320ea53ca682c010de6ed1102edcd021ceb4822a5785033a500786fe",
|
||||
"MachineLearning/CameraDirector/train.py": "070d1c4159c56a2107ae0d383ab0b716b12c13186d45383e94b83d3ba6305d03",
|
||||
"MachineLearning/CameraDirector/trajectory_quality.py": "20cd2ddc1b2349f8c33f6d1460580f37964a521eaa86ceee5b8ae457512ba49d"
|
||||
},
|
||||
"preparationLogicIdentifier": "1cb808e207d54854267a1020a658812c79e9bad5a5296f78140228b3a15eeb3b",
|
||||
"candidateLogicIdentifier": "e768283e8496360ff703b5135f85c51520a888787612b15456def131d5ee1d89",
|
||||
"generationCodeIdentifier": "80e9eeca5aed9e17a9cfb61b235f954ed4eb24308a1a1ca962e424dbb54bea88",
|
||||
"generationCodeFiles": [
|
||||
"adjacent_transition.py",
|
||||
"camera_kinematics.py",
|
||||
"camera_runtime_data.py",
|
||||
"data_driven_cut_planner.py",
|
||||
"generate_hybrid.py",
|
||||
"hybrid_cut_reference.py",
|
||||
"planner.py",
|
||||
"shot_features.py",
|
||||
"trajectory_quality.py"
|
||||
]
|
||||
}
|
||||
|
||||
+28
-1
@@ -710,11 +710,12 @@ def dependency_checks() -> list[dict[str, Any]]:
|
||||
|
||||
def doctor_payload(runtime_root: Path) -> dict[str, Any]:
|
||||
runtime_root = Path(runtime_root).resolve()
|
||||
training_index_path = runtime_root / "reports" / "training_index.json"
|
||||
resources = (
|
||||
("datasetRoot", runtime_root / "DatasetExports", "directory"),
|
||||
(
|
||||
"trainingIndex",
|
||||
runtime_root / "reports" / "training_index.json",
|
||||
training_index_path,
|
||||
"file",
|
||||
),
|
||||
(
|
||||
@@ -727,6 +728,32 @@ def doctor_payload(runtime_root: Path) -> dict[str, Any]:
|
||||
for name, path, kind in resources:
|
||||
ok = path.is_dir() if kind == "directory" else path.is_file()
|
||||
checks.append({"name": name, "ok": ok, "detail": str(path)})
|
||||
if training_index_path.is_file():
|
||||
try:
|
||||
generator = importlib.import_module("generate_hybrid")
|
||||
training_index = json.loads(
|
||||
training_index_path.read_text(encoding="utf-8")
|
||||
)
|
||||
catalog_path = generator.validate_training_index_catalog_freshness(
|
||||
training_index_path,
|
||||
training_index,
|
||||
)
|
||||
except Exception as error:
|
||||
checks.append(
|
||||
{
|
||||
"name": "trainingIndexCatalogFreshness",
|
||||
"ok": False,
|
||||
"detail": f"{type(error).__name__}: {error}",
|
||||
}
|
||||
)
|
||||
else:
|
||||
checks.append(
|
||||
{
|
||||
"name": "trainingIndexCatalogFreshness",
|
||||
"ok": True,
|
||||
"detail": str(catalog_path),
|
||||
}
|
||||
)
|
||||
if cw_camera_runtime.is_frozen_runtime():
|
||||
identity = cw_camera_runtime.load_build_identity()
|
||||
checks.append(
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ from typing import Any, Iterable
|
||||
|
||||
BUILD_IDENTITY_SCHEMA_VERSION = "cw-camera-worker-build-identity-v1"
|
||||
BUILD_IDENTITY_FILE = "cw_camera_worker_build_identity.json"
|
||||
WORKER_VERSION = "0.1.7"
|
||||
WORKER_VERSION = "0.1.8"
|
||||
|
||||
|
||||
def is_frozen_runtime() -> bool:
|
||||
|
||||
+39
-2
@@ -50,6 +50,10 @@ import cw_camera_runtime
|
||||
import trajectory_quality
|
||||
|
||||
|
||||
GIT_LFS_POINTER_PREFIX = "version https://git-lfs.github.com/spec/v1"
|
||||
UTF8_BOM = "\ufeff"
|
||||
|
||||
|
||||
HARD_PERSON_SAFE_BOUNDS = {
|
||||
"wide": (0.1, 0.9, 0.12, 0.86),
|
||||
"medium": (0.12, 0.88, 0.12, 0.84),
|
||||
@@ -8675,8 +8679,41 @@ def validate_training_index_catalog_freshness(
|
||||
raise FileNotFoundError(
|
||||
f"Training-index catalog was not found. Searched: {searched}"
|
||||
)
|
||||
actual_sha256 = sha256_file(resolved_catalog).lower()
|
||||
if actual_sha256 != expected_sha256:
|
||||
catalog_bytes = resolved_catalog.read_bytes()
|
||||
pointer_probe = catalog_bytes
|
||||
utf8_bom = UTF8_BOM.encode("utf-8")
|
||||
if pointer_probe.startswith(utf8_bom):
|
||||
pointer_probe = pointer_probe[len(utf8_bom) :]
|
||||
if pointer_probe.startswith(GIT_LFS_POINTER_PREFIX.encode("ascii")):
|
||||
raise ValueError(
|
||||
"Training-index catalog is still a Git LFS pointer: "
|
||||
f"{resolved_catalog}. Materialize Git LFS assets and retry."
|
||||
)
|
||||
|
||||
actual_sha256 = hashlib.sha256(catalog_bytes).hexdigest().lower()
|
||||
catalog_matches = actual_sha256 == expected_sha256
|
||||
if not catalog_matches:
|
||||
try:
|
||||
catalog_bytes.decode("utf-8", errors="strict")
|
||||
except UnicodeDecodeError:
|
||||
normalized_sha256 = None
|
||||
else:
|
||||
all_cr_bytes_are_crlf = all(
|
||||
offset + 1 < len(catalog_bytes)
|
||||
and catalog_bytes[offset + 1] == 0x0A
|
||||
for offset, value in enumerate(catalog_bytes)
|
||||
if value == 0x0D
|
||||
)
|
||||
if all_cr_bytes_are_crlf:
|
||||
normalized_bytes = catalog_bytes.replace(b"\r\n", b"\n")
|
||||
normalized_sha256 = hashlib.sha256(
|
||||
normalized_bytes
|
||||
).hexdigest().lower()
|
||||
else:
|
||||
normalized_sha256 = None
|
||||
catalog_matches = normalized_sha256 == expected_sha256
|
||||
|
||||
if not catalog_matches:
|
||||
raise ValueError(
|
||||
"Training index is stale: catalog SHA-256 mismatch for "
|
||||
f"{resolved_catalog}. Expected {expected_sha256}, got {actual_sha256}. "
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+32
-32
@@ -1,32 +1,32 @@
|
||||
importlib_metadata-8.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
importlib_metadata-8.0.0.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
||||
importlib_metadata-8.0.0.dist-info/METADATA,sha256=anuQ7_7h4J1bSEzfcjIBakPi2cyVQ7y7jklLHsBeH1k,4648
|
||||
importlib_metadata-8.0.0.dist-info/RECORD,,
|
||||
importlib_metadata-8.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
importlib_metadata-8.0.0.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
|
||||
importlib_metadata-8.0.0.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
|
||||
importlib_metadata/__init__.py,sha256=tZNB-23h8Bixi9uCrQqj9Yf0aeC--Josdy3IZRIQeB0,33798
|
||||
importlib_metadata/__pycache__/__init__.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_adapters.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_collections.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_compat.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_functools.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_itertools.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_meta.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_text.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/diagnose.cpython-312.pyc,,
|
||||
importlib_metadata/_adapters.py,sha256=rIhWTwBvYA1bV7i-5FfVX38qEXDTXFeS5cb5xJtP3ks,2317
|
||||
importlib_metadata/_collections.py,sha256=CJ0OTCHIjWA0ZIVS4voORAsn2R4R2cQBEtPsZEJpASY,743
|
||||
importlib_metadata/_compat.py,sha256=73QKrN9KNoaZzhbX5yPCCZa-FaALwXe8TPlDR72JgBU,1314
|
||||
importlib_metadata/_functools.py,sha256=PsY2-4rrKX4RVeRC1oGp1lB1pmC9eKN88_f-bD9uOoA,2895
|
||||
importlib_metadata/_itertools.py,sha256=cvr_2v8BRbxcIl5x5ldfqdHjhI8Yi8s8yk50G_nm6jQ,2068
|
||||
importlib_metadata/_meta.py,sha256=nxZ7C8GVlcBFAKWyVOn_dn7ot_twBcbm1NmvjIetBHI,1801
|
||||
importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166
|
||||
importlib_metadata/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
importlib_metadata/compat/__pycache__/__init__.cpython-312.pyc,,
|
||||
importlib_metadata/compat/__pycache__/py311.cpython-312.pyc,,
|
||||
importlib_metadata/compat/__pycache__/py39.cpython-312.pyc,,
|
||||
importlib_metadata/compat/py311.py,sha256=uqm-K-uohyj1042TH4a9Er_I5o7667DvulcD-gC_fSA,608
|
||||
importlib_metadata/compat/py39.py,sha256=cPkMv6-0ilK-0Jw_Tkn0xYbOKJZc4WJKQHow0c2T44w,1102
|
||||
importlib_metadata/diagnose.py,sha256=nkSRMiowlmkhLYhKhvCg9glmt_11Cox-EmLzEbqYTa8,379
|
||||
importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
importlib_metadata-8.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
importlib_metadata-8.0.0.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
||||
importlib_metadata-8.0.0.dist-info/METADATA,sha256=anuQ7_7h4J1bSEzfcjIBakPi2cyVQ7y7jklLHsBeH1k,4648
|
||||
importlib_metadata-8.0.0.dist-info/RECORD,,
|
||||
importlib_metadata-8.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
importlib_metadata-8.0.0.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
|
||||
importlib_metadata-8.0.0.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
|
||||
importlib_metadata/__init__.py,sha256=tZNB-23h8Bixi9uCrQqj9Yf0aeC--Josdy3IZRIQeB0,33798
|
||||
importlib_metadata/__pycache__/__init__.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_adapters.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_collections.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_compat.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_functools.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_itertools.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_meta.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_text.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/diagnose.cpython-312.pyc,,
|
||||
importlib_metadata/_adapters.py,sha256=rIhWTwBvYA1bV7i-5FfVX38qEXDTXFeS5cb5xJtP3ks,2317
|
||||
importlib_metadata/_collections.py,sha256=CJ0OTCHIjWA0ZIVS4voORAsn2R4R2cQBEtPsZEJpASY,743
|
||||
importlib_metadata/_compat.py,sha256=73QKrN9KNoaZzhbX5yPCCZa-FaALwXe8TPlDR72JgBU,1314
|
||||
importlib_metadata/_functools.py,sha256=PsY2-4rrKX4RVeRC1oGp1lB1pmC9eKN88_f-bD9uOoA,2895
|
||||
importlib_metadata/_itertools.py,sha256=cvr_2v8BRbxcIl5x5ldfqdHjhI8Yi8s8yk50G_nm6jQ,2068
|
||||
importlib_metadata/_meta.py,sha256=nxZ7C8GVlcBFAKWyVOn_dn7ot_twBcbm1NmvjIetBHI,1801
|
||||
importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166
|
||||
importlib_metadata/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
importlib_metadata/compat/__pycache__/__init__.cpython-312.pyc,,
|
||||
importlib_metadata/compat/__pycache__/py311.cpython-312.pyc,,
|
||||
importlib_metadata/compat/__pycache__/py39.cpython-312.pyc,,
|
||||
importlib_metadata/compat/py311.py,sha256=uqm-K-uohyj1042TH4a9Er_I5o7667DvulcD-gC_fSA,608
|
||||
importlib_metadata/compat/py39.py,sha256=cPkMv6-0ilK-0Jw_Tkn0xYbOKJZc4WJKQHow0c2T44w,1102
|
||||
importlib_metadata/diagnose.py,sha256=nkSRMiowlmkhLYhKhvCg9glmt_11Cox-EmLzEbqYTa8,379
|
||||
importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
def check_build():
|
||||
return
|
||||
def check_build():
|
||||
return
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
py.extension_module(
|
||||
'_check_build',
|
||||
cython_gen.process('_check_build.pyx'),
|
||||
install: true,
|
||||
subdir: 'sklearn/__check_build',
|
||||
)
|
||||
py.extension_module(
|
||||
'_check_build',
|
||||
cython_gen.process('_check_build.pyx'),
|
||||
install: true,
|
||||
subdir: 'sklearn/__check_build',
|
||||
)
|
||||
|
||||
@@ -1,116 +1,116 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Uses the pool adjacent violators algorithm (PAVA), with the
|
||||
# enhancement of searching for the longest decreasing subsequence to
|
||||
# pool at each step.
|
||||
|
||||
import numpy as np
|
||||
from cython cimport floating
|
||||
|
||||
|
||||
def _inplace_contiguous_isotonic_regression(floating[::1] y, floating[::1] w):
|
||||
cdef:
|
||||
Py_ssize_t n = y.shape[0], i, k
|
||||
floating prev_y, sum_wy, sum_w
|
||||
Py_ssize_t[::1] target = np.arange(n, dtype=np.intp)
|
||||
|
||||
# target describes a list of blocks. At any time, if [i..j] (inclusive) is
|
||||
# an active block, then target[i] := j and target[j] := i.
|
||||
|
||||
# For "active" indices (block starts):
|
||||
# w[i] := sum{w_orig[j], j=[i..target[i]]}
|
||||
# y[i] := sum{y_orig[j]*w_orig[j], j=[i..target[i]]} / w[i]
|
||||
|
||||
with nogil:
|
||||
i = 0
|
||||
while i < n:
|
||||
k = target[i] + 1
|
||||
if k == n:
|
||||
break
|
||||
if y[i] < y[k]:
|
||||
i = k
|
||||
continue
|
||||
sum_wy = w[i] * y[i]
|
||||
sum_w = w[i]
|
||||
while True:
|
||||
# We are within a decreasing subsequence.
|
||||
prev_y = y[k]
|
||||
sum_wy += w[k] * y[k]
|
||||
sum_w += w[k]
|
||||
k = target[k] + 1
|
||||
if k == n or prev_y < y[k]:
|
||||
# Non-singleton decreasing subsequence is finished,
|
||||
# update first entry.
|
||||
y[i] = sum_wy / sum_w
|
||||
w[i] = sum_w
|
||||
target[i] = k - 1
|
||||
target[k - 1] = i
|
||||
if i > 0:
|
||||
# Backtrack if we can. This makes the algorithm
|
||||
# single-pass and ensures O(n) complexity.
|
||||
i = target[i - 1]
|
||||
# Otherwise, restart from the same point.
|
||||
break
|
||||
# Reconstruct the solution.
|
||||
i = 0
|
||||
while i < n:
|
||||
k = target[i] + 1
|
||||
y[i + 1 : k] = y[i]
|
||||
i = k
|
||||
|
||||
|
||||
def _make_unique(const floating[::1] X,
|
||||
const floating[::1] y,
|
||||
const floating[::1] sample_weights):
|
||||
"""Average targets for duplicate X, drop duplicates.
|
||||
|
||||
Aggregates duplicate X values into a single X value where
|
||||
the target y is a (sample_weighted) average of the individual
|
||||
targets.
|
||||
|
||||
Assumes that X is ordered, so that all duplicates follow each other.
|
||||
"""
|
||||
unique_values = len(np.unique(X))
|
||||
|
||||
if floating is float:
|
||||
dtype = np.float32
|
||||
else:
|
||||
dtype = np.float64
|
||||
|
||||
cdef floating[::1] y_out = np.empty(unique_values, dtype=dtype)
|
||||
cdef floating[::1] x_out = np.empty_like(y_out)
|
||||
cdef floating[::1] weights_out = np.empty_like(y_out)
|
||||
|
||||
cdef floating current_x = X[0]
|
||||
cdef floating current_y = 0
|
||||
cdef floating current_weight = 0
|
||||
cdef int i = 0
|
||||
cdef int j
|
||||
cdef floating x
|
||||
cdef int n_samples = len(X)
|
||||
cdef floating eps = np.finfo(dtype).resolution
|
||||
|
||||
for j in range(n_samples):
|
||||
x = X[j]
|
||||
if x - current_x >= eps:
|
||||
# next unique value
|
||||
x_out[i] = current_x
|
||||
weights_out[i] = current_weight
|
||||
y_out[i] = current_y / current_weight
|
||||
i += 1
|
||||
current_x = x
|
||||
current_weight = sample_weights[j]
|
||||
current_y = y[j] * sample_weights[j]
|
||||
else:
|
||||
current_weight += sample_weights[j]
|
||||
current_y += y[j] * sample_weights[j]
|
||||
|
||||
x_out[i] = current_x
|
||||
weights_out[i] = current_weight
|
||||
y_out[i] = current_y / current_weight
|
||||
return(
|
||||
np.asarray(x_out[:i+1]),
|
||||
np.asarray(y_out[:i+1]),
|
||||
np.asarray(weights_out[:i+1]),
|
||||
)
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Uses the pool adjacent violators algorithm (PAVA), with the
|
||||
# enhancement of searching for the longest decreasing subsequence to
|
||||
# pool at each step.
|
||||
|
||||
import numpy as np
|
||||
from cython cimport floating
|
||||
|
||||
|
||||
def _inplace_contiguous_isotonic_regression(floating[::1] y, floating[::1] w):
|
||||
cdef:
|
||||
Py_ssize_t n = y.shape[0], i, k
|
||||
floating prev_y, sum_wy, sum_w
|
||||
Py_ssize_t[::1] target = np.arange(n, dtype=np.intp)
|
||||
|
||||
# target describes a list of blocks. At any time, if [i..j] (inclusive) is
|
||||
# an active block, then target[i] := j and target[j] := i.
|
||||
|
||||
# For "active" indices (block starts):
|
||||
# w[i] := sum{w_orig[j], j=[i..target[i]]}
|
||||
# y[i] := sum{y_orig[j]*w_orig[j], j=[i..target[i]]} / w[i]
|
||||
|
||||
with nogil:
|
||||
i = 0
|
||||
while i < n:
|
||||
k = target[i] + 1
|
||||
if k == n:
|
||||
break
|
||||
if y[i] < y[k]:
|
||||
i = k
|
||||
continue
|
||||
sum_wy = w[i] * y[i]
|
||||
sum_w = w[i]
|
||||
while True:
|
||||
# We are within a decreasing subsequence.
|
||||
prev_y = y[k]
|
||||
sum_wy += w[k] * y[k]
|
||||
sum_w += w[k]
|
||||
k = target[k] + 1
|
||||
if k == n or prev_y < y[k]:
|
||||
# Non-singleton decreasing subsequence is finished,
|
||||
# update first entry.
|
||||
y[i] = sum_wy / sum_w
|
||||
w[i] = sum_w
|
||||
target[i] = k - 1
|
||||
target[k - 1] = i
|
||||
if i > 0:
|
||||
# Backtrack if we can. This makes the algorithm
|
||||
# single-pass and ensures O(n) complexity.
|
||||
i = target[i - 1]
|
||||
# Otherwise, restart from the same point.
|
||||
break
|
||||
# Reconstruct the solution.
|
||||
i = 0
|
||||
while i < n:
|
||||
k = target[i] + 1
|
||||
y[i + 1 : k] = y[i]
|
||||
i = k
|
||||
|
||||
|
||||
def _make_unique(const floating[::1] X,
|
||||
const floating[::1] y,
|
||||
const floating[::1] sample_weights):
|
||||
"""Average targets for duplicate X, drop duplicates.
|
||||
|
||||
Aggregates duplicate X values into a single X value where
|
||||
the target y is a (sample_weighted) average of the individual
|
||||
targets.
|
||||
|
||||
Assumes that X is ordered, so that all duplicates follow each other.
|
||||
"""
|
||||
unique_values = len(np.unique(X))
|
||||
|
||||
if floating is float:
|
||||
dtype = np.float32
|
||||
else:
|
||||
dtype = np.float64
|
||||
|
||||
cdef floating[::1] y_out = np.empty(unique_values, dtype=dtype)
|
||||
cdef floating[::1] x_out = np.empty_like(y_out)
|
||||
cdef floating[::1] weights_out = np.empty_like(y_out)
|
||||
|
||||
cdef floating current_x = X[0]
|
||||
cdef floating current_y = 0
|
||||
cdef floating current_weight = 0
|
||||
cdef int i = 0
|
||||
cdef int j
|
||||
cdef floating x
|
||||
cdef int n_samples = len(X)
|
||||
cdef floating eps = np.finfo(dtype).resolution
|
||||
|
||||
for j in range(n_samples):
|
||||
x = X[j]
|
||||
if x - current_x >= eps:
|
||||
# next unique value
|
||||
x_out[i] = current_x
|
||||
weights_out[i] = current_weight
|
||||
y_out[i] = current_y / current_weight
|
||||
i += 1
|
||||
current_x = x
|
||||
current_weight = sample_weights[j]
|
||||
current_y = y[j] * sample_weights[j]
|
||||
else:
|
||||
current_weight += sample_weights[j]
|
||||
current_y += y[j] * sample_weights[j]
|
||||
|
||||
x_out[i] = current_x
|
||||
weights_out[i] = current_weight
|
||||
y_out[i] = current_y / current_weight
|
||||
return(
|
||||
np.asarray(x_out[:i+1]),
|
||||
np.asarray(y_out[:i+1]),
|
||||
np.asarray(weights_out[:i+1]),
|
||||
)
|
||||
|
||||
@@ -1,101 +1,101 @@
|
||||
# Fused types for input like y_true, raw_prediction, sample_weights.
|
||||
ctypedef fused floating_in:
|
||||
double
|
||||
float
|
||||
|
||||
|
||||
# Fused types for output like gradient and hessian
|
||||
# We use a different fused types for input (floating_in) and output (floating_out), such
|
||||
# that input and output can have different dtypes in the same function call. A single
|
||||
# fused type can only take on one single value (type) for all arguments in one function
|
||||
# call.
|
||||
ctypedef fused floating_out:
|
||||
double
|
||||
float
|
||||
|
||||
|
||||
# Struct to return 2 doubles
|
||||
ctypedef struct double_pair:
|
||||
double val1
|
||||
double val2
|
||||
|
||||
|
||||
# C base class for loss functions
|
||||
cdef class CyLossFunction:
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfSquaredError(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyAbsoluteError(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyPinballLoss(CyLossFunction):
|
||||
cdef readonly double quantile # readonly makes it accessible from Python
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHuberLoss(CyLossFunction):
|
||||
cdef public double delta # public makes it accessible from Python
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfPoissonLoss(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfGammaLoss(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfTweedieLoss(CyLossFunction):
|
||||
cdef readonly double power # readonly makes it accessible from Python
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfTweedieLossIdentity(CyLossFunction):
|
||||
cdef readonly double power # readonly makes it accessible from Python
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfBinomialLoss(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyExponentialLoss(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfMultinomialLoss():
|
||||
cdef void cy_gradient(
|
||||
self,
|
||||
const floating_in y_true,
|
||||
const floating_in[::1] raw_prediction,
|
||||
const floating_in sample_weight,
|
||||
floating_out[::1] gradient_out,
|
||||
) noexcept nogil
|
||||
# Fused types for input like y_true, raw_prediction, sample_weights.
|
||||
ctypedef fused floating_in:
|
||||
double
|
||||
float
|
||||
|
||||
|
||||
# Fused types for output like gradient and hessian
|
||||
# We use a different fused types for input (floating_in) and output (floating_out), such
|
||||
# that input and output can have different dtypes in the same function call. A single
|
||||
# fused type can only take on one single value (type) for all arguments in one function
|
||||
# call.
|
||||
ctypedef fused floating_out:
|
||||
double
|
||||
float
|
||||
|
||||
|
||||
# Struct to return 2 doubles
|
||||
ctypedef struct double_pair:
|
||||
double val1
|
||||
double val2
|
||||
|
||||
|
||||
# C base class for loss functions
|
||||
cdef class CyLossFunction:
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfSquaredError(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyAbsoluteError(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyPinballLoss(CyLossFunction):
|
||||
cdef readonly double quantile # readonly makes it accessible from Python
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHuberLoss(CyLossFunction):
|
||||
cdef public double delta # public makes it accessible from Python
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfPoissonLoss(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfGammaLoss(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfTweedieLoss(CyLossFunction):
|
||||
cdef readonly double power # readonly makes it accessible from Python
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfTweedieLossIdentity(CyLossFunction):
|
||||
cdef readonly double power # readonly makes it accessible from Python
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfBinomialLoss(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyExponentialLoss(CyLossFunction):
|
||||
cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double cy_gradient(self, double y_true, double raw_prediction) noexcept nogil
|
||||
cdef double_pair cy_grad_hess(self, double y_true, double raw_prediction) noexcept nogil
|
||||
|
||||
|
||||
cdef class CyHalfMultinomialLoss():
|
||||
cdef void cy_gradient(
|
||||
self,
|
||||
const floating_in y_true,
|
||||
const floating_in[::1] raw_prediction,
|
||||
const floating_in sample_weight,
|
||||
floating_out[::1] gradient_out,
|
||||
) noexcept nogil
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,23 @@
|
||||
# .pyx is generated, so this is needed to make Cython compilation work
|
||||
_loss_cython_tree = [
|
||||
fs.copyfile('_loss.pxd')
|
||||
]
|
||||
|
||||
_loss_pyx = custom_target(
|
||||
'_loss_pyx',
|
||||
output: '_loss.pyx',
|
||||
input: '_loss.pyx.tp',
|
||||
command: [tempita, '@INPUT@', '-o', '@OUTDIR@'],
|
||||
# TODO in principle this should go in py.exension_module below. This is
|
||||
# temporary work-around for dependency issue with .pyx.tp files. For more
|
||||
# details, see https://github.com/mesonbuild/meson/issues/13212
|
||||
depends: _loss_cython_tree,
|
||||
)
|
||||
|
||||
py.extension_module(
|
||||
'_loss',
|
||||
cython_gen.process(_loss_pyx),
|
||||
dependencies: [openmp_dep],
|
||||
install: true,
|
||||
subdir: 'sklearn/_loss',
|
||||
)
|
||||
# .pyx is generated, so this is needed to make Cython compilation work
|
||||
_loss_cython_tree = [
|
||||
fs.copyfile('_loss.pxd')
|
||||
]
|
||||
|
||||
_loss_pyx = custom_target(
|
||||
'_loss_pyx',
|
||||
output: '_loss.pyx',
|
||||
input: '_loss.pyx.tp',
|
||||
command: [tempita, '@INPUT@', '-o', '@OUTDIR@'],
|
||||
# TODO in principle this should go in py.exension_module below. This is
|
||||
# temporary work-around for dependency issue with .pyx.tp files. For more
|
||||
# details, see https://github.com/mesonbuild/meson/issues/13212
|
||||
depends: _loss_cython_tree,
|
||||
)
|
||||
|
||||
py.extension_module(
|
||||
'_loss',
|
||||
cython_gen.process(_loss_pyx),
|
||||
dependencies: [openmp_dep],
|
||||
install: true,
|
||||
subdir: 'sklearn/_loss',
|
||||
)
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
# Fast inner loop for DBSCAN.
|
||||
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from libcpp.vector cimport vector
|
||||
|
||||
from ..utils._typedefs cimport uint8_t, intp_t
|
||||
|
||||
|
||||
def dbscan_inner(const uint8_t[::1] is_core,
|
||||
object[:] neighborhoods,
|
||||
intp_t[::1] labels):
|
||||
cdef intp_t i, label_num = 0, v
|
||||
cdef intp_t[:] neighb
|
||||
cdef vector[intp_t] stack
|
||||
|
||||
for i in range(labels.shape[0]):
|
||||
if labels[i] != -1 or not is_core[i]:
|
||||
continue
|
||||
|
||||
# Depth-first search starting from i, ending at the non-core points.
|
||||
# This is very similar to the classic algorithm for computing connected
|
||||
# components, the difference being that we label non-core points as
|
||||
# part of a cluster (component), but don't expand their neighborhoods.
|
||||
while True:
|
||||
if labels[i] == -1:
|
||||
labels[i] = label_num
|
||||
if is_core[i]:
|
||||
neighb = neighborhoods[i]
|
||||
for i in range(neighb.shape[0]):
|
||||
v = neighb[i]
|
||||
if labels[v] == -1:
|
||||
stack.push_back(v)
|
||||
|
||||
if stack.size() == 0:
|
||||
break
|
||||
i = stack.back()
|
||||
stack.pop_back()
|
||||
|
||||
label_num += 1
|
||||
# Fast inner loop for DBSCAN.
|
||||
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from libcpp.vector cimport vector
|
||||
|
||||
from ..utils._typedefs cimport uint8_t, intp_t
|
||||
|
||||
|
||||
def dbscan_inner(const uint8_t[::1] is_core,
|
||||
object[:] neighborhoods,
|
||||
intp_t[::1] labels):
|
||||
cdef intp_t i, label_num = 0, v
|
||||
cdef intp_t[:] neighb
|
||||
cdef vector[intp_t] stack
|
||||
|
||||
for i in range(labels.shape[0]):
|
||||
if labels[i] != -1 or not is_core[i]:
|
||||
continue
|
||||
|
||||
# Depth-first search starting from i, ending at the non-core points.
|
||||
# This is very similar to the classic algorithm for computing connected
|
||||
# components, the difference being that we label non-core points as
|
||||
# part of a cluster (component), but don't expand their neighborhoods.
|
||||
while True:
|
||||
if labels[i] == -1:
|
||||
labels[i] = label_num
|
||||
if is_core[i]:
|
||||
neighb = neighborhoods[i]
|
||||
for i in range(neighb.shape[0]):
|
||||
v = neighb[i]
|
||||
if labels[v] == -1:
|
||||
stack.push_back(v)
|
||||
|
||||
if stack.size() == 0:
|
||||
break
|
||||
i = stack.back()
|
||||
stack.pop_back()
|
||||
|
||||
label_num += 1
|
||||
|
||||
@@ -1,274 +1,274 @@
|
||||
# Minimum spanning tree single linkage implementation for hdbscan
|
||||
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
cimport numpy as cnp
|
||||
from libc.float cimport DBL_MAX
|
||||
|
||||
import numpy as np
|
||||
from ...metrics._dist_metrics cimport DistanceMetric64
|
||||
from ...cluster._hierarchical_fast cimport UnionFind
|
||||
from ...cluster._hdbscan._tree cimport HIERARCHY_t
|
||||
from ...cluster._hdbscan._tree import HIERARCHY_dtype
|
||||
from ...utils._typedefs cimport intp_t, float64_t, int64_t, uint8_t
|
||||
|
||||
cnp.import_array()
|
||||
|
||||
cdef extern from "numpy/arrayobject.h":
|
||||
intp_t * PyArray_SHAPE(cnp.PyArrayObject *)
|
||||
|
||||
# Numpy structured dtype representing a single ordered edge in Prim's algorithm
|
||||
MST_edge_dtype = np.dtype([
|
||||
("current_node", np.int64),
|
||||
("next_node", np.int64),
|
||||
("distance", np.float64),
|
||||
])
|
||||
|
||||
# Packed shouldn't make a difference since they're all 8-byte quantities,
|
||||
# but it's included just to be safe.
|
||||
ctypedef packed struct MST_edge_t:
|
||||
int64_t current_node
|
||||
int64_t next_node
|
||||
float64_t distance
|
||||
|
||||
cpdef cnp.ndarray[MST_edge_t, ndim=1, mode='c'] mst_from_mutual_reachability(
|
||||
cnp.ndarray[float64_t, ndim=2] mutual_reachability
|
||||
):
|
||||
"""Compute the Minimum Spanning Tree (MST) representation of the mutual-
|
||||
reachability graph using Prim's algorithm.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mutual_reachability : ndarray of shape (n_samples, n_samples)
|
||||
Array of mutual-reachabilities between samples.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mst : ndarray of shape (n_samples - 1,), dtype=MST_edge_dtype
|
||||
The MST representation of the mutual-reachability graph. The MST is
|
||||
represented as a collection of edges.
|
||||
"""
|
||||
cdef:
|
||||
# Note: we utilize ndarray's over memory-views to make use of numpy
|
||||
# binary indexing and sub-selection below.
|
||||
cnp.ndarray[int64_t, ndim=1, mode='c'] current_labels
|
||||
cnp.ndarray[float64_t, ndim=1, mode='c'] min_reachability, left, right
|
||||
cnp.ndarray[MST_edge_t, ndim=1, mode='c'] mst
|
||||
|
||||
cnp.ndarray[uint8_t, mode='c'] label_filter
|
||||
|
||||
int64_t n_samples = PyArray_SHAPE(<cnp.PyArrayObject*> mutual_reachability)[0]
|
||||
int64_t current_node, new_node_index, new_node, i
|
||||
|
||||
mst = np.empty(n_samples - 1, dtype=MST_edge_dtype)
|
||||
current_labels = np.arange(n_samples, dtype=np.int64)
|
||||
current_node = 0
|
||||
min_reachability = np.full(n_samples, fill_value=np.inf, dtype=np.float64)
|
||||
for i in range(0, n_samples - 1):
|
||||
label_filter = current_labels != current_node
|
||||
current_labels = current_labels[label_filter]
|
||||
left = min_reachability[label_filter]
|
||||
right = mutual_reachability[current_node][current_labels]
|
||||
min_reachability = np.minimum(left, right)
|
||||
|
||||
new_node_index = np.argmin(min_reachability)
|
||||
new_node = current_labels[new_node_index]
|
||||
mst[i].current_node = current_node
|
||||
mst[i].next_node = new_node
|
||||
mst[i].distance = min_reachability[new_node_index]
|
||||
current_node = new_node
|
||||
|
||||
return mst
|
||||
|
||||
|
||||
cpdef cnp.ndarray[MST_edge_t, ndim=1, mode='c'] mst_from_data_matrix(
|
||||
const float64_t[:, ::1] raw_data,
|
||||
const float64_t[::1] core_distances,
|
||||
DistanceMetric64 dist_metric,
|
||||
float64_t alpha=1.0
|
||||
):
|
||||
"""Compute the Minimum Spanning Tree (MST) representation of the mutual-
|
||||
reachability graph generated from the provided `raw_data` and
|
||||
`core_distances` using Prim's algorithm.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
raw_data : ndarray of shape (n_samples, n_features)
|
||||
Input array of data samples.
|
||||
|
||||
core_distances : ndarray of shape (n_samples,)
|
||||
An array containing the core-distance calculated for each corresponding
|
||||
sample.
|
||||
|
||||
dist_metric : DistanceMetric
|
||||
The distance metric to use when calculating pairwise distances for
|
||||
determining mutual-reachability.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mst : ndarray of shape (n_samples - 1,), dtype=MST_edge_dtype
|
||||
The MST representation of the mutual-reachability graph. The MST is
|
||||
represented as a collection of edges.
|
||||
"""
|
||||
|
||||
cdef:
|
||||
uint8_t[::1] in_tree
|
||||
float64_t[::1] min_reachability
|
||||
int64_t[::1] current_sources
|
||||
cnp.ndarray[MST_edge_t, ndim=1, mode='c'] mst
|
||||
|
||||
int64_t current_node, source_node, new_node, next_node_source
|
||||
int64_t i, j, n_samples, num_features
|
||||
|
||||
float64_t current_node_core_dist, new_reachability, mutual_reachability_distance
|
||||
float64_t next_node_min_reach, pair_distance, next_node_core_dist
|
||||
|
||||
n_samples = raw_data.shape[0]
|
||||
num_features = raw_data.shape[1]
|
||||
|
||||
mst = np.empty(n_samples - 1, dtype=MST_edge_dtype)
|
||||
|
||||
in_tree = np.zeros(n_samples, dtype=np.uint8)
|
||||
min_reachability = np.full(n_samples, fill_value=np.inf, dtype=np.float64)
|
||||
current_sources = np.ones(n_samples, dtype=np.int64)
|
||||
|
||||
current_node = 0
|
||||
|
||||
# The following loop dynamically updates minimum reachability node-by-node,
|
||||
# avoiding unnecessary computation where possible.
|
||||
for i in range(0, n_samples - 1):
|
||||
|
||||
in_tree[current_node] = 1
|
||||
|
||||
current_node_core_dist = core_distances[current_node]
|
||||
|
||||
new_reachability = DBL_MAX
|
||||
source_node = 0
|
||||
new_node = 0
|
||||
|
||||
for j in range(n_samples):
|
||||
if in_tree[j]:
|
||||
continue
|
||||
|
||||
next_node_min_reach = min_reachability[j]
|
||||
next_node_source = current_sources[j]
|
||||
|
||||
pair_distance = dist_metric.dist(
|
||||
&raw_data[current_node, 0],
|
||||
&raw_data[j, 0],
|
||||
num_features
|
||||
)
|
||||
|
||||
pair_distance /= alpha
|
||||
|
||||
next_node_core_dist = core_distances[j]
|
||||
mutual_reachability_distance = max(
|
||||
current_node_core_dist,
|
||||
next_node_core_dist,
|
||||
pair_distance
|
||||
)
|
||||
|
||||
# If MRD(i, j) is smaller than node j's min_reachability, we update
|
||||
# node j's min_reachability for future reference.
|
||||
if mutual_reachability_distance < next_node_min_reach:
|
||||
min_reachability[j] = mutual_reachability_distance
|
||||
current_sources[j] = current_node
|
||||
|
||||
# If MRD(i, j) is also smaller than node i's current
|
||||
# min_reachability, we update and set their edge as the current
|
||||
# MST edge candidate.
|
||||
if mutual_reachability_distance < new_reachability:
|
||||
new_reachability = mutual_reachability_distance
|
||||
source_node = current_node
|
||||
new_node = j
|
||||
|
||||
# If the node j is closer to another node already in the tree, we
|
||||
# make their edge the current MST candidate edge.
|
||||
elif next_node_min_reach < new_reachability:
|
||||
new_reachability = next_node_min_reach
|
||||
source_node = next_node_source
|
||||
new_node = j
|
||||
|
||||
mst[i].current_node = source_node
|
||||
mst[i].next_node = new_node
|
||||
mst[i].distance = new_reachability
|
||||
current_node = new_node
|
||||
|
||||
return mst
|
||||
|
||||
cpdef cnp.ndarray[HIERARCHY_t, ndim=1, mode="c"] make_single_linkage(const MST_edge_t[::1] mst):
|
||||
"""Construct a single-linkage tree from an MST.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mst : ndarray of shape (n_samples - 1,), dtype=MST_edge_dtype
|
||||
The MST representation of the mutual-reachability graph. The MST is
|
||||
represented as a collection of edges.
|
||||
|
||||
Returns
|
||||
-------
|
||||
single_linkage : ndarray of shape (n_samples - 1,), dtype=HIERARCHY_dtype
|
||||
The single-linkage tree tree (dendrogram) built from the MST. Each
|
||||
of the array represents the following:
|
||||
|
||||
- left node/cluster
|
||||
- right node/cluster
|
||||
- distance
|
||||
- new cluster size
|
||||
"""
|
||||
cdef:
|
||||
cnp.ndarray[HIERARCHY_t, ndim=1, mode="c"] single_linkage
|
||||
|
||||
# Note mst.shape[0] is one fewer than the number of samples
|
||||
int64_t n_samples = mst.shape[0] + 1
|
||||
intp_t current_node_cluster, next_node_cluster
|
||||
int64_t current_node, next_node, i
|
||||
float64_t distance
|
||||
UnionFind U = UnionFind(n_samples)
|
||||
|
||||
single_linkage = np.zeros(n_samples - 1, dtype=HIERARCHY_dtype)
|
||||
|
||||
for i in range(n_samples - 1):
|
||||
|
||||
current_node = mst[i].current_node
|
||||
next_node = mst[i].next_node
|
||||
distance = mst[i].distance
|
||||
|
||||
current_node_cluster = U.fast_find(current_node)
|
||||
next_node_cluster = U.fast_find(next_node)
|
||||
|
||||
single_linkage[i].left_node = current_node_cluster
|
||||
single_linkage[i].right_node = next_node_cluster
|
||||
single_linkage[i].value = distance
|
||||
single_linkage[i].cluster_size = U.size[current_node_cluster] + U.size[next_node_cluster]
|
||||
|
||||
U.union(current_node_cluster, next_node_cluster)
|
||||
|
||||
return single_linkage
|
||||
# Minimum spanning tree single linkage implementation for hdbscan
|
||||
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
cimport numpy as cnp
|
||||
from libc.float cimport DBL_MAX
|
||||
|
||||
import numpy as np
|
||||
from ...metrics._dist_metrics cimport DistanceMetric64
|
||||
from ...cluster._hierarchical_fast cimport UnionFind
|
||||
from ...cluster._hdbscan._tree cimport HIERARCHY_t
|
||||
from ...cluster._hdbscan._tree import HIERARCHY_dtype
|
||||
from ...utils._typedefs cimport intp_t, float64_t, int64_t, uint8_t
|
||||
|
||||
cnp.import_array()
|
||||
|
||||
cdef extern from "numpy/arrayobject.h":
|
||||
intp_t * PyArray_SHAPE(cnp.PyArrayObject *)
|
||||
|
||||
# Numpy structured dtype representing a single ordered edge in Prim's algorithm
|
||||
MST_edge_dtype = np.dtype([
|
||||
("current_node", np.int64),
|
||||
("next_node", np.int64),
|
||||
("distance", np.float64),
|
||||
])
|
||||
|
||||
# Packed shouldn't make a difference since they're all 8-byte quantities,
|
||||
# but it's included just to be safe.
|
||||
ctypedef packed struct MST_edge_t:
|
||||
int64_t current_node
|
||||
int64_t next_node
|
||||
float64_t distance
|
||||
|
||||
cpdef cnp.ndarray[MST_edge_t, ndim=1, mode='c'] mst_from_mutual_reachability(
|
||||
cnp.ndarray[float64_t, ndim=2] mutual_reachability
|
||||
):
|
||||
"""Compute the Minimum Spanning Tree (MST) representation of the mutual-
|
||||
reachability graph using Prim's algorithm.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mutual_reachability : ndarray of shape (n_samples, n_samples)
|
||||
Array of mutual-reachabilities between samples.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mst : ndarray of shape (n_samples - 1,), dtype=MST_edge_dtype
|
||||
The MST representation of the mutual-reachability graph. The MST is
|
||||
represented as a collection of edges.
|
||||
"""
|
||||
cdef:
|
||||
# Note: we utilize ndarray's over memory-views to make use of numpy
|
||||
# binary indexing and sub-selection below.
|
||||
cnp.ndarray[int64_t, ndim=1, mode='c'] current_labels
|
||||
cnp.ndarray[float64_t, ndim=1, mode='c'] min_reachability, left, right
|
||||
cnp.ndarray[MST_edge_t, ndim=1, mode='c'] mst
|
||||
|
||||
cnp.ndarray[uint8_t, mode='c'] label_filter
|
||||
|
||||
int64_t n_samples = PyArray_SHAPE(<cnp.PyArrayObject*> mutual_reachability)[0]
|
||||
int64_t current_node, new_node_index, new_node, i
|
||||
|
||||
mst = np.empty(n_samples - 1, dtype=MST_edge_dtype)
|
||||
current_labels = np.arange(n_samples, dtype=np.int64)
|
||||
current_node = 0
|
||||
min_reachability = np.full(n_samples, fill_value=np.inf, dtype=np.float64)
|
||||
for i in range(0, n_samples - 1):
|
||||
label_filter = current_labels != current_node
|
||||
current_labels = current_labels[label_filter]
|
||||
left = min_reachability[label_filter]
|
||||
right = mutual_reachability[current_node][current_labels]
|
||||
min_reachability = np.minimum(left, right)
|
||||
|
||||
new_node_index = np.argmin(min_reachability)
|
||||
new_node = current_labels[new_node_index]
|
||||
mst[i].current_node = current_node
|
||||
mst[i].next_node = new_node
|
||||
mst[i].distance = min_reachability[new_node_index]
|
||||
current_node = new_node
|
||||
|
||||
return mst
|
||||
|
||||
|
||||
cpdef cnp.ndarray[MST_edge_t, ndim=1, mode='c'] mst_from_data_matrix(
|
||||
const float64_t[:, ::1] raw_data,
|
||||
const float64_t[::1] core_distances,
|
||||
DistanceMetric64 dist_metric,
|
||||
float64_t alpha=1.0
|
||||
):
|
||||
"""Compute the Minimum Spanning Tree (MST) representation of the mutual-
|
||||
reachability graph generated from the provided `raw_data` and
|
||||
`core_distances` using Prim's algorithm.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
raw_data : ndarray of shape (n_samples, n_features)
|
||||
Input array of data samples.
|
||||
|
||||
core_distances : ndarray of shape (n_samples,)
|
||||
An array containing the core-distance calculated for each corresponding
|
||||
sample.
|
||||
|
||||
dist_metric : DistanceMetric
|
||||
The distance metric to use when calculating pairwise distances for
|
||||
determining mutual-reachability.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mst : ndarray of shape (n_samples - 1,), dtype=MST_edge_dtype
|
||||
The MST representation of the mutual-reachability graph. The MST is
|
||||
represented as a collection of edges.
|
||||
"""
|
||||
|
||||
cdef:
|
||||
uint8_t[::1] in_tree
|
||||
float64_t[::1] min_reachability
|
||||
int64_t[::1] current_sources
|
||||
cnp.ndarray[MST_edge_t, ndim=1, mode='c'] mst
|
||||
|
||||
int64_t current_node, source_node, new_node, next_node_source
|
||||
int64_t i, j, n_samples, num_features
|
||||
|
||||
float64_t current_node_core_dist, new_reachability, mutual_reachability_distance
|
||||
float64_t next_node_min_reach, pair_distance, next_node_core_dist
|
||||
|
||||
n_samples = raw_data.shape[0]
|
||||
num_features = raw_data.shape[1]
|
||||
|
||||
mst = np.empty(n_samples - 1, dtype=MST_edge_dtype)
|
||||
|
||||
in_tree = np.zeros(n_samples, dtype=np.uint8)
|
||||
min_reachability = np.full(n_samples, fill_value=np.inf, dtype=np.float64)
|
||||
current_sources = np.ones(n_samples, dtype=np.int64)
|
||||
|
||||
current_node = 0
|
||||
|
||||
# The following loop dynamically updates minimum reachability node-by-node,
|
||||
# avoiding unnecessary computation where possible.
|
||||
for i in range(0, n_samples - 1):
|
||||
|
||||
in_tree[current_node] = 1
|
||||
|
||||
current_node_core_dist = core_distances[current_node]
|
||||
|
||||
new_reachability = DBL_MAX
|
||||
source_node = 0
|
||||
new_node = 0
|
||||
|
||||
for j in range(n_samples):
|
||||
if in_tree[j]:
|
||||
continue
|
||||
|
||||
next_node_min_reach = min_reachability[j]
|
||||
next_node_source = current_sources[j]
|
||||
|
||||
pair_distance = dist_metric.dist(
|
||||
&raw_data[current_node, 0],
|
||||
&raw_data[j, 0],
|
||||
num_features
|
||||
)
|
||||
|
||||
pair_distance /= alpha
|
||||
|
||||
next_node_core_dist = core_distances[j]
|
||||
mutual_reachability_distance = max(
|
||||
current_node_core_dist,
|
||||
next_node_core_dist,
|
||||
pair_distance
|
||||
)
|
||||
|
||||
# If MRD(i, j) is smaller than node j's min_reachability, we update
|
||||
# node j's min_reachability for future reference.
|
||||
if mutual_reachability_distance < next_node_min_reach:
|
||||
min_reachability[j] = mutual_reachability_distance
|
||||
current_sources[j] = current_node
|
||||
|
||||
# If MRD(i, j) is also smaller than node i's current
|
||||
# min_reachability, we update and set their edge as the current
|
||||
# MST edge candidate.
|
||||
if mutual_reachability_distance < new_reachability:
|
||||
new_reachability = mutual_reachability_distance
|
||||
source_node = current_node
|
||||
new_node = j
|
||||
|
||||
# If the node j is closer to another node already in the tree, we
|
||||
# make their edge the current MST candidate edge.
|
||||
elif next_node_min_reach < new_reachability:
|
||||
new_reachability = next_node_min_reach
|
||||
source_node = next_node_source
|
||||
new_node = j
|
||||
|
||||
mst[i].current_node = source_node
|
||||
mst[i].next_node = new_node
|
||||
mst[i].distance = new_reachability
|
||||
current_node = new_node
|
||||
|
||||
return mst
|
||||
|
||||
cpdef cnp.ndarray[HIERARCHY_t, ndim=1, mode="c"] make_single_linkage(const MST_edge_t[::1] mst):
|
||||
"""Construct a single-linkage tree from an MST.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mst : ndarray of shape (n_samples - 1,), dtype=MST_edge_dtype
|
||||
The MST representation of the mutual-reachability graph. The MST is
|
||||
represented as a collection of edges.
|
||||
|
||||
Returns
|
||||
-------
|
||||
single_linkage : ndarray of shape (n_samples - 1,), dtype=HIERARCHY_dtype
|
||||
The single-linkage tree tree (dendrogram) built from the MST. Each
|
||||
of the array represents the following:
|
||||
|
||||
- left node/cluster
|
||||
- right node/cluster
|
||||
- distance
|
||||
- new cluster size
|
||||
"""
|
||||
cdef:
|
||||
cnp.ndarray[HIERARCHY_t, ndim=1, mode="c"] single_linkage
|
||||
|
||||
# Note mst.shape[0] is one fewer than the number of samples
|
||||
int64_t n_samples = mst.shape[0] + 1
|
||||
intp_t current_node_cluster, next_node_cluster
|
||||
int64_t current_node, next_node, i
|
||||
float64_t distance
|
||||
UnionFind U = UnionFind(n_samples)
|
||||
|
||||
single_linkage = np.zeros(n_samples - 1, dtype=HIERARCHY_dtype)
|
||||
|
||||
for i in range(n_samples - 1):
|
||||
|
||||
current_node = mst[i].current_node
|
||||
next_node = mst[i].next_node
|
||||
distance = mst[i].distance
|
||||
|
||||
current_node_cluster = U.fast_find(current_node)
|
||||
next_node_cluster = U.fast_find(next_node)
|
||||
|
||||
single_linkage[i].left_node = current_node_cluster
|
||||
single_linkage[i].right_node = next_node_cluster
|
||||
single_linkage[i].value = distance
|
||||
single_linkage[i].cluster_size = U.size[current_node_cluster] + U.size[next_node_cluster]
|
||||
|
||||
U.union(current_node_cluster, next_node_cluster)
|
||||
|
||||
return single_linkage
|
||||
|
||||
+210
-210
@@ -1,210 +1,210 @@
|
||||
# mutual reachability distance computations
|
||||
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
cimport numpy as cnp
|
||||
|
||||
import numpy as np
|
||||
from scipy.sparse import issparse
|
||||
from cython cimport floating, integral
|
||||
from libc.math cimport isfinite, INFINITY
|
||||
from ...utils._typedefs cimport intp_t
|
||||
cnp.import_array()
|
||||
|
||||
|
||||
def mutual_reachability_graph(
|
||||
distance_matrix, min_samples=5, max_distance=0.0
|
||||
):
|
||||
"""Compute the weighted adjacency matrix of the mutual reachability graph.
|
||||
|
||||
The mutual reachability distance used to build the graph is defined as::
|
||||
|
||||
max(d_core(x_p), d_core(x_q), d(x_p, x_q))
|
||||
|
||||
and the core distance `d_core` is defined as the distance between a point
|
||||
`x_p` and its k-th nearest neighbor.
|
||||
|
||||
Note that all computations are done in-place.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
distance_matrix : {ndarray, sparse matrix} of shape (n_samples, n_samples)
|
||||
Array of distances between samples. If sparse, the array must be in
|
||||
`CSR` format.
|
||||
|
||||
min_samples : int, default=5
|
||||
The parameter `k` used to calculate the distance between a point
|
||||
`x_p` and its k-th nearest neighbor.
|
||||
|
||||
max_distance : float, default=0.0
|
||||
The distance which `np.inf` is replaced with. When the true mutual-
|
||||
reachability distance is measured to be infinite, it is instead
|
||||
truncated to `max_dist`. Only used when `distance_matrix` is a sparse
|
||||
matrix.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mututal_reachability_graph: {ndarray, sparse matrix} of shape \
|
||||
(n_samples, n_samples)
|
||||
Weighted adjacency matrix of the mutual reachability graph.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Campello, R. J., Moulavi, D., & Sander, J. (2013, April).
|
||||
Density-based clustering based on hierarchical density estimates.
|
||||
In Pacific-Asia Conference on Knowledge Discovery and Data Mining
|
||||
(pp. 160-172). Springer Berlin Heidelberg.
|
||||
"""
|
||||
further_neighbor_idx = min_samples - 1
|
||||
if issparse(distance_matrix):
|
||||
if distance_matrix.format != "csr":
|
||||
raise ValueError(
|
||||
"Only sparse CSR matrices are supported for `distance_matrix`."
|
||||
)
|
||||
_sparse_mutual_reachability_graph(
|
||||
distance_matrix.data,
|
||||
distance_matrix.indices,
|
||||
distance_matrix.indptr,
|
||||
distance_matrix.shape[0],
|
||||
further_neighbor_idx=further_neighbor_idx,
|
||||
max_distance=max_distance,
|
||||
)
|
||||
else:
|
||||
_dense_mutual_reachability_graph(
|
||||
distance_matrix, further_neighbor_idx=further_neighbor_idx
|
||||
)
|
||||
return distance_matrix
|
||||
|
||||
|
||||
def _dense_mutual_reachability_graph(
|
||||
floating[:, :] distance_matrix,
|
||||
intp_t further_neighbor_idx,
|
||||
):
|
||||
"""Dense implementation of mutual reachability graph.
|
||||
|
||||
The computation is done in-place, i.e. the distance matrix is modified
|
||||
directly.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
distance_matrix : ndarray of shape (n_samples, n_samples)
|
||||
Array of distances between samples.
|
||||
|
||||
further_neighbor_idx : int
|
||||
The index of the furthest neighbor to use to define the core distances.
|
||||
"""
|
||||
cdef:
|
||||
intp_t i, j, n_samples = distance_matrix.shape[0]
|
||||
floating mutual_reachability_distance
|
||||
floating[::1] core_distances
|
||||
|
||||
# We assume that the distance matrix is symmetric. We choose to sort every
|
||||
# row to have the same implementation than the sparse case that requires
|
||||
# CSR matrix.
|
||||
core_distances = np.ascontiguousarray(
|
||||
np.partition(
|
||||
distance_matrix, further_neighbor_idx, axis=1
|
||||
)[:, further_neighbor_idx]
|
||||
)
|
||||
|
||||
with nogil:
|
||||
# TODO: Update w/ prange with thread count based on
|
||||
# _openmp_effective_n_threads
|
||||
for i in range(n_samples):
|
||||
for j in range(n_samples):
|
||||
mutual_reachability_distance = max(
|
||||
core_distances[i],
|
||||
core_distances[j],
|
||||
distance_matrix[i, j],
|
||||
)
|
||||
distance_matrix[i, j] = mutual_reachability_distance
|
||||
|
||||
|
||||
def _sparse_mutual_reachability_graph(
|
||||
cnp.ndarray[floating, ndim=1, mode="c"] data,
|
||||
cnp.ndarray[integral, ndim=1, mode="c"] indices,
|
||||
cnp.ndarray[integral, ndim=1, mode="c"] indptr,
|
||||
intp_t n_samples,
|
||||
intp_t further_neighbor_idx,
|
||||
floating max_distance,
|
||||
):
|
||||
"""Sparse implementation of mutual reachability graph.
|
||||
|
||||
The computation is done in-place, i.e. the distance matrix is modified
|
||||
directly. This implementation only accepts `CSR` format sparse matrices.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
distance_matrix : sparse matrix of shape (n_samples, n_samples)
|
||||
Sparse matrix of distances between samples. The sparse format should
|
||||
be `CSR`.
|
||||
|
||||
further_neighbor_idx : int
|
||||
The index of the furthest neighbor to use to define the core distances.
|
||||
|
||||
max_distance : float
|
||||
The distance which `np.inf` is replaced with. When the true mutual-
|
||||
reachability distance is measured to be infinite, it is instead
|
||||
truncated to `max_dist`. Only used when `distance_matrix` is a sparse
|
||||
matrix.
|
||||
"""
|
||||
cdef:
|
||||
integral i, col_ind, row_ind
|
||||
floating mutual_reachability_distance
|
||||
floating[:] core_distances
|
||||
floating[:] row_data
|
||||
|
||||
if floating is float:
|
||||
dtype = np.float32
|
||||
else:
|
||||
dtype = np.float64
|
||||
|
||||
core_distances = np.empty(n_samples, dtype=dtype)
|
||||
|
||||
for i in range(n_samples):
|
||||
row_data = data[indptr[i]:indptr[i + 1]]
|
||||
if further_neighbor_idx < row_data.size:
|
||||
core_distances[i] = np.partition(
|
||||
row_data, further_neighbor_idx
|
||||
)[further_neighbor_idx]
|
||||
else:
|
||||
core_distances[i] = INFINITY
|
||||
|
||||
with nogil:
|
||||
for row_ind in range(n_samples):
|
||||
for i in range(indptr[row_ind], indptr[row_ind + 1]):
|
||||
col_ind = indices[i]
|
||||
mutual_reachability_distance = max(
|
||||
core_distances[row_ind], core_distances[col_ind], data[i]
|
||||
)
|
||||
if isfinite(mutual_reachability_distance):
|
||||
data[i] = mutual_reachability_distance
|
||||
elif max_distance > 0:
|
||||
data[i] = max_distance
|
||||
# mutual reachability distance computations
|
||||
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
cimport numpy as cnp
|
||||
|
||||
import numpy as np
|
||||
from scipy.sparse import issparse
|
||||
from cython cimport floating, integral
|
||||
from libc.math cimport isfinite, INFINITY
|
||||
from ...utils._typedefs cimport intp_t
|
||||
cnp.import_array()
|
||||
|
||||
|
||||
def mutual_reachability_graph(
|
||||
distance_matrix, min_samples=5, max_distance=0.0
|
||||
):
|
||||
"""Compute the weighted adjacency matrix of the mutual reachability graph.
|
||||
|
||||
The mutual reachability distance used to build the graph is defined as::
|
||||
|
||||
max(d_core(x_p), d_core(x_q), d(x_p, x_q))
|
||||
|
||||
and the core distance `d_core` is defined as the distance between a point
|
||||
`x_p` and its k-th nearest neighbor.
|
||||
|
||||
Note that all computations are done in-place.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
distance_matrix : {ndarray, sparse matrix} of shape (n_samples, n_samples)
|
||||
Array of distances between samples. If sparse, the array must be in
|
||||
`CSR` format.
|
||||
|
||||
min_samples : int, default=5
|
||||
The parameter `k` used to calculate the distance between a point
|
||||
`x_p` and its k-th nearest neighbor.
|
||||
|
||||
max_distance : float, default=0.0
|
||||
The distance which `np.inf` is replaced with. When the true mutual-
|
||||
reachability distance is measured to be infinite, it is instead
|
||||
truncated to `max_dist`. Only used when `distance_matrix` is a sparse
|
||||
matrix.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mututal_reachability_graph: {ndarray, sparse matrix} of shape \
|
||||
(n_samples, n_samples)
|
||||
Weighted adjacency matrix of the mutual reachability graph.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Campello, R. J., Moulavi, D., & Sander, J. (2013, April).
|
||||
Density-based clustering based on hierarchical density estimates.
|
||||
In Pacific-Asia Conference on Knowledge Discovery and Data Mining
|
||||
(pp. 160-172). Springer Berlin Heidelberg.
|
||||
"""
|
||||
further_neighbor_idx = min_samples - 1
|
||||
if issparse(distance_matrix):
|
||||
if distance_matrix.format != "csr":
|
||||
raise ValueError(
|
||||
"Only sparse CSR matrices are supported for `distance_matrix`."
|
||||
)
|
||||
_sparse_mutual_reachability_graph(
|
||||
distance_matrix.data,
|
||||
distance_matrix.indices,
|
||||
distance_matrix.indptr,
|
||||
distance_matrix.shape[0],
|
||||
further_neighbor_idx=further_neighbor_idx,
|
||||
max_distance=max_distance,
|
||||
)
|
||||
else:
|
||||
_dense_mutual_reachability_graph(
|
||||
distance_matrix, further_neighbor_idx=further_neighbor_idx
|
||||
)
|
||||
return distance_matrix
|
||||
|
||||
|
||||
def _dense_mutual_reachability_graph(
|
||||
floating[:, :] distance_matrix,
|
||||
intp_t further_neighbor_idx,
|
||||
):
|
||||
"""Dense implementation of mutual reachability graph.
|
||||
|
||||
The computation is done in-place, i.e. the distance matrix is modified
|
||||
directly.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
distance_matrix : ndarray of shape (n_samples, n_samples)
|
||||
Array of distances between samples.
|
||||
|
||||
further_neighbor_idx : int
|
||||
The index of the furthest neighbor to use to define the core distances.
|
||||
"""
|
||||
cdef:
|
||||
intp_t i, j, n_samples = distance_matrix.shape[0]
|
||||
floating mutual_reachability_distance
|
||||
floating[::1] core_distances
|
||||
|
||||
# We assume that the distance matrix is symmetric. We choose to sort every
|
||||
# row to have the same implementation than the sparse case that requires
|
||||
# CSR matrix.
|
||||
core_distances = np.ascontiguousarray(
|
||||
np.partition(
|
||||
distance_matrix, further_neighbor_idx, axis=1
|
||||
)[:, further_neighbor_idx]
|
||||
)
|
||||
|
||||
with nogil:
|
||||
# TODO: Update w/ prange with thread count based on
|
||||
# _openmp_effective_n_threads
|
||||
for i in range(n_samples):
|
||||
for j in range(n_samples):
|
||||
mutual_reachability_distance = max(
|
||||
core_distances[i],
|
||||
core_distances[j],
|
||||
distance_matrix[i, j],
|
||||
)
|
||||
distance_matrix[i, j] = mutual_reachability_distance
|
||||
|
||||
|
||||
def _sparse_mutual_reachability_graph(
|
||||
cnp.ndarray[floating, ndim=1, mode="c"] data,
|
||||
cnp.ndarray[integral, ndim=1, mode="c"] indices,
|
||||
cnp.ndarray[integral, ndim=1, mode="c"] indptr,
|
||||
intp_t n_samples,
|
||||
intp_t further_neighbor_idx,
|
||||
floating max_distance,
|
||||
):
|
||||
"""Sparse implementation of mutual reachability graph.
|
||||
|
||||
The computation is done in-place, i.e. the distance matrix is modified
|
||||
directly. This implementation only accepts `CSR` format sparse matrices.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
distance_matrix : sparse matrix of shape (n_samples, n_samples)
|
||||
Sparse matrix of distances between samples. The sparse format should
|
||||
be `CSR`.
|
||||
|
||||
further_neighbor_idx : int
|
||||
The index of the furthest neighbor to use to define the core distances.
|
||||
|
||||
max_distance : float
|
||||
The distance which `np.inf` is replaced with. When the true mutual-
|
||||
reachability distance is measured to be infinite, it is instead
|
||||
truncated to `max_dist`. Only used when `distance_matrix` is a sparse
|
||||
matrix.
|
||||
"""
|
||||
cdef:
|
||||
integral i, col_ind, row_ind
|
||||
floating mutual_reachability_distance
|
||||
floating[:] core_distances
|
||||
floating[:] row_data
|
||||
|
||||
if floating is float:
|
||||
dtype = np.float32
|
||||
else:
|
||||
dtype = np.float64
|
||||
|
||||
core_distances = np.empty(n_samples, dtype=dtype)
|
||||
|
||||
for i in range(n_samples):
|
||||
row_data = data[indptr[i]:indptr[i + 1]]
|
||||
if further_neighbor_idx < row_data.size:
|
||||
core_distances[i] = np.partition(
|
||||
row_data, further_neighbor_idx
|
||||
)[further_neighbor_idx]
|
||||
else:
|
||||
core_distances[i] = INFINITY
|
||||
|
||||
with nogil:
|
||||
for row_ind in range(n_samples):
|
||||
for i in range(indptr[row_ind], indptr[row_ind + 1]):
|
||||
col_ind = indices[i]
|
||||
mutual_reachability_distance = max(
|
||||
core_distances[row_ind], core_distances[col_ind], data[i]
|
||||
)
|
||||
if isfinite(mutual_reachability_distance):
|
||||
data[i] = mutual_reachability_distance
|
||||
elif max_distance > 0:
|
||||
data[i] = max_distance
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
# Copyright (c) 2015, Leland McInnes
|
||||
# All rights reserved.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from ...utils._typedefs cimport intp_t, float64_t, uint8_t
|
||||
cimport numpy as cnp
|
||||
|
||||
# This corresponds to the scipy.cluster.hierarchy format
|
||||
ctypedef packed struct HIERARCHY_t:
|
||||
intp_t left_node
|
||||
intp_t right_node
|
||||
float64_t value
|
||||
intp_t cluster_size
|
||||
|
||||
# Effectively an edgelist encoding a parent/child pair, along with a value and
|
||||
# the corresponding cluster_size in each row providing a tree structure.
|
||||
ctypedef packed struct CONDENSED_t:
|
||||
intp_t parent
|
||||
intp_t child
|
||||
float64_t value
|
||||
intp_t cluster_size
|
||||
|
||||
cdef extern from "numpy/arrayobject.h":
|
||||
intp_t * PyArray_SHAPE(cnp.PyArrayObject *)
|
||||
# Copyright (c) 2015, Leland McInnes
|
||||
# All rights reserved.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from ...utils._typedefs cimport intp_t, float64_t, uint8_t
|
||||
cimport numpy as cnp
|
||||
|
||||
# This corresponds to the scipy.cluster.hierarchy format
|
||||
ctypedef packed struct HIERARCHY_t:
|
||||
intp_t left_node
|
||||
intp_t right_node
|
||||
float64_t value
|
||||
intp_t cluster_size
|
||||
|
||||
# Effectively an edgelist encoding a parent/child pair, along with a value and
|
||||
# the corresponding cluster_size in each row providing a tree structure.
|
||||
ctypedef packed struct CONDENSED_t:
|
||||
intp_t parent
|
||||
intp_t child
|
||||
float64_t value
|
||||
intp_t cluster_size
|
||||
|
||||
cdef extern from "numpy/arrayobject.h":
|
||||
intp_t * PyArray_SHAPE(cnp.PyArrayObject *)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,15 @@
|
||||
cluster_hdbscan_extension_metadata = {
|
||||
'_linkage': {'sources': [cython_gen.process('_linkage.pyx'), metrics_cython_tree]},
|
||||
'_reachability': {'sources': [cython_gen.process('_reachability.pyx')]},
|
||||
'_tree': {'sources': [cython_gen.process('_tree.pyx')]}
|
||||
}
|
||||
|
||||
foreach ext_name, ext_dict : cluster_hdbscan_extension_metadata
|
||||
py.extension_module(
|
||||
ext_name,
|
||||
ext_dict.get('sources'),
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/cluster/_hdbscan',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
cluster_hdbscan_extension_metadata = {
|
||||
'_linkage': {'sources': [cython_gen.process('_linkage.pyx'), metrics_cython_tree]},
|
||||
'_reachability': {'sources': [cython_gen.process('_reachability.pyx')]},
|
||||
'_tree': {'sources': [cython_gen.process('_tree.pyx')]}
|
||||
}
|
||||
|
||||
foreach ext_name, ext_dict : cluster_hdbscan_extension_metadata
|
||||
py.extension_module(
|
||||
ext_name,
|
||||
ext_dict.get('sources'),
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/cluster/_hdbscan',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from ..utils._typedefs cimport intp_t
|
||||
|
||||
cdef class UnionFind:
|
||||
cdef intp_t next_label
|
||||
cdef intp_t[:] parent
|
||||
cdef intp_t[:] size
|
||||
|
||||
cdef void union(self, intp_t m, intp_t n) noexcept
|
||||
cdef intp_t fast_find(self, intp_t n) noexcept
|
||||
from ..utils._typedefs cimport intp_t
|
||||
|
||||
cdef class UnionFind:
|
||||
cdef intp_t next_label
|
||||
cdef intp_t[:] parent
|
||||
cdef intp_t[:] size
|
||||
|
||||
cdef void union(self, intp_t m, intp_t n) noexcept
|
||||
cdef intp_t fast_find(self, intp_t n) noexcept
|
||||
|
||||
+507
-507
File diff suppressed because it is too large
Load Diff
@@ -1,48 +1,48 @@
|
||||
from cython cimport floating
|
||||
|
||||
|
||||
cdef floating _euclidean_dense_dense(
|
||||
const floating*,
|
||||
const floating*,
|
||||
int,
|
||||
bint
|
||||
) noexcept nogil
|
||||
|
||||
cdef floating _euclidean_sparse_dense(
|
||||
const floating[::1],
|
||||
const int[::1],
|
||||
const floating[::1],
|
||||
floating,
|
||||
bint
|
||||
) noexcept nogil
|
||||
|
||||
cpdef void _relocate_empty_clusters_dense(
|
||||
const floating[:, ::1],
|
||||
const floating[::1],
|
||||
const floating[:, ::1],
|
||||
floating[:, ::1],
|
||||
floating[::1],
|
||||
const int[::1]
|
||||
)
|
||||
|
||||
cpdef void _relocate_empty_clusters_sparse(
|
||||
const floating[::1],
|
||||
const int[::1],
|
||||
const int[::1],
|
||||
const floating[::1],
|
||||
const floating[:, ::1],
|
||||
floating[:, ::1],
|
||||
floating[::1],
|
||||
const int[::1]
|
||||
)
|
||||
|
||||
cdef void _average_centers(
|
||||
floating[:, ::1],
|
||||
const floating[::1]
|
||||
)
|
||||
|
||||
cdef void _center_shift(
|
||||
const floating[:, ::1],
|
||||
const floating[:, ::1],
|
||||
floating[::1]
|
||||
)
|
||||
from cython cimport floating
|
||||
|
||||
|
||||
cdef floating _euclidean_dense_dense(
|
||||
const floating*,
|
||||
const floating*,
|
||||
int,
|
||||
bint
|
||||
) noexcept nogil
|
||||
|
||||
cdef floating _euclidean_sparse_dense(
|
||||
const floating[::1],
|
||||
const int[::1],
|
||||
const floating[::1],
|
||||
floating,
|
||||
bint
|
||||
) noexcept nogil
|
||||
|
||||
cpdef void _relocate_empty_clusters_dense(
|
||||
const floating[:, ::1],
|
||||
const floating[::1],
|
||||
const floating[:, ::1],
|
||||
floating[:, ::1],
|
||||
floating[::1],
|
||||
const int[::1]
|
||||
)
|
||||
|
||||
cpdef void _relocate_empty_clusters_sparse(
|
||||
const floating[::1],
|
||||
const int[::1],
|
||||
const int[::1],
|
||||
const floating[::1],
|
||||
const floating[:, ::1],
|
||||
floating[:, ::1],
|
||||
floating[::1],
|
||||
const int[::1]
|
||||
)
|
||||
|
||||
cdef void _average_centers(
|
||||
floating[:, ::1],
|
||||
const floating[::1]
|
||||
)
|
||||
|
||||
cdef void _center_shift(
|
||||
const floating[:, ::1],
|
||||
const floating[:, ::1],
|
||||
floating[::1]
|
||||
)
|
||||
|
||||
@@ -1,328 +1,328 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import numpy as np
|
||||
from cython cimport floating
|
||||
from cython.parallel cimport prange
|
||||
from libc.math cimport sqrt
|
||||
|
||||
from ..utils.extmath import row_norms
|
||||
|
||||
|
||||
# Number of samples per data chunk defined as a global constant.
|
||||
CHUNK_SIZE = 256
|
||||
|
||||
|
||||
cdef floating _euclidean_dense_dense(
|
||||
const floating* a, # IN
|
||||
const floating* b, # IN
|
||||
int n_features,
|
||||
bint squared
|
||||
) noexcept nogil:
|
||||
"""Euclidean distance between a dense and b dense"""
|
||||
cdef:
|
||||
int i
|
||||
int n = n_features // 4
|
||||
int rem = n_features % 4
|
||||
floating result = 0
|
||||
|
||||
# We manually unroll the loop for better cache optimization.
|
||||
for i in range(n):
|
||||
result += (
|
||||
(a[0] - b[0]) * (a[0] - b[0]) +
|
||||
(a[1] - b[1]) * (a[1] - b[1]) +
|
||||
(a[2] - b[2]) * (a[2] - b[2]) +
|
||||
(a[3] - b[3]) * (a[3] - b[3])
|
||||
)
|
||||
a += 4
|
||||
b += 4
|
||||
|
||||
for i in range(rem):
|
||||
result += (a[i] - b[i]) * (a[i] - b[i])
|
||||
|
||||
return result if squared else sqrt(result)
|
||||
|
||||
|
||||
def _euclidean_dense_dense_wrapper(
|
||||
const floating[::1] a,
|
||||
const floating[::1] b,
|
||||
bint squared
|
||||
):
|
||||
"""Wrapper of _euclidean_dense_dense for testing purpose"""
|
||||
return _euclidean_dense_dense(&a[0], &b[0], a.shape[0], squared)
|
||||
|
||||
|
||||
cdef floating _euclidean_sparse_dense(
|
||||
const floating[::1] a_data, # IN
|
||||
const int[::1] a_indices, # IN
|
||||
const floating[::1] b, # IN
|
||||
floating b_squared_norm,
|
||||
bint squared
|
||||
) noexcept nogil:
|
||||
"""Euclidean distance between a sparse and b dense"""
|
||||
cdef:
|
||||
int nnz = a_indices.shape[0]
|
||||
int i
|
||||
floating tmp, bi
|
||||
floating result = 0.0
|
||||
|
||||
for i in range(nnz):
|
||||
bi = b[a_indices[i]]
|
||||
tmp = a_data[i] - bi
|
||||
result += tmp * tmp - bi * bi
|
||||
|
||||
result += b_squared_norm
|
||||
|
||||
if result < 0:
|
||||
result = 0.0
|
||||
|
||||
return result if squared else sqrt(result)
|
||||
|
||||
|
||||
def _euclidean_sparse_dense_wrapper(
|
||||
const floating[::1] a_data,
|
||||
const int[::1] a_indices,
|
||||
const floating[::1] b,
|
||||
floating b_squared_norm,
|
||||
bint squared
|
||||
):
|
||||
"""Wrapper of _euclidean_sparse_dense for testing purpose"""
|
||||
return _euclidean_sparse_dense(
|
||||
a_data, a_indices, b, b_squared_norm, squared)
|
||||
|
||||
|
||||
cpdef floating _inertia_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers, # IN
|
||||
const int[::1] labels, # IN
|
||||
int n_threads,
|
||||
int single_label=-1,
|
||||
):
|
||||
"""Compute inertia for dense input data
|
||||
|
||||
Sum of squared distance between each sample and its assigned center.
|
||||
|
||||
If single_label is >= 0, the inertia is computed only for that label.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = X.shape[0]
|
||||
int n_features = X.shape[1]
|
||||
int i, j
|
||||
|
||||
floating sq_dist = 0.0
|
||||
floating inertia = 0.0
|
||||
|
||||
for i in prange(n_samples, nogil=True, num_threads=n_threads,
|
||||
schedule='static'):
|
||||
j = labels[i]
|
||||
if single_label < 0 or single_label == j:
|
||||
sq_dist = _euclidean_dense_dense(&X[i, 0], ¢ers[j, 0],
|
||||
n_features, True)
|
||||
inertia += sq_dist * sample_weight[i]
|
||||
|
||||
return inertia
|
||||
|
||||
|
||||
cpdef floating _inertia_sparse(
|
||||
X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers, # IN
|
||||
const int[::1] labels, # IN
|
||||
int n_threads,
|
||||
int single_label=-1,
|
||||
):
|
||||
"""Compute inertia for sparse input data
|
||||
|
||||
Sum of squared distance between each sample and its assigned center.
|
||||
|
||||
If single_label is >= 0, the inertia is computed only for that label.
|
||||
"""
|
||||
cdef:
|
||||
floating[::1] X_data = X.data
|
||||
int[::1] X_indices = X.indices
|
||||
int[::1] X_indptr = X.indptr
|
||||
|
||||
int n_samples = X.shape[0]
|
||||
int i, j
|
||||
|
||||
floating sq_dist = 0.0
|
||||
floating inertia = 0.0
|
||||
|
||||
floating[::1] centers_squared_norms = row_norms(centers, squared=True)
|
||||
|
||||
for i in prange(n_samples, nogil=True, num_threads=n_threads,
|
||||
schedule='static'):
|
||||
j = labels[i]
|
||||
if single_label < 0 or single_label == j:
|
||||
sq_dist = _euclidean_sparse_dense(
|
||||
X_data[X_indptr[i]: X_indptr[i + 1]],
|
||||
X_indices[X_indptr[i]: X_indptr[i + 1]],
|
||||
centers[j], centers_squared_norms[j], True)
|
||||
inertia += sq_dist * sample_weight[i]
|
||||
|
||||
return inertia
|
||||
|
||||
|
||||
cpdef void _relocate_empty_clusters_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # INOUT
|
||||
floating[::1] weight_in_clusters, # INOUT
|
||||
const int[::1] labels # IN
|
||||
):
|
||||
"""Relocate centers which have no sample assigned to them."""
|
||||
cdef:
|
||||
int[::1] empty_clusters = np.where(np.equal(weight_in_clusters, 0))[0].astype(np.int32)
|
||||
int n_empty = empty_clusters.shape[0]
|
||||
|
||||
if n_empty == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
int n_features = X.shape[1]
|
||||
|
||||
floating[::1] distances = ((np.asarray(X) - np.asarray(centers_old)[labels])**2).sum(axis=1)
|
||||
int[::1] far_from_centers = np.argpartition(distances, -n_empty)[:-n_empty-1:-1].astype(np.int32)
|
||||
|
||||
int new_cluster_id, old_cluster_id, far_idx, idx, k
|
||||
floating weight
|
||||
|
||||
if np.max(distances) == 0:
|
||||
# Happens when there are more clusters than non-duplicate samples. Relocating
|
||||
# is pointless in this case.
|
||||
return
|
||||
|
||||
for idx in range(n_empty):
|
||||
|
||||
new_cluster_id = empty_clusters[idx]
|
||||
|
||||
far_idx = far_from_centers[idx]
|
||||
weight = sample_weight[far_idx]
|
||||
|
||||
old_cluster_id = labels[far_idx]
|
||||
|
||||
for k in range(n_features):
|
||||
centers_new[old_cluster_id, k] -= X[far_idx, k] * weight
|
||||
centers_new[new_cluster_id, k] = X[far_idx, k] * weight
|
||||
|
||||
weight_in_clusters[new_cluster_id] = weight
|
||||
weight_in_clusters[old_cluster_id] -= weight
|
||||
|
||||
|
||||
cpdef void _relocate_empty_clusters_sparse(
|
||||
const floating[::1] X_data, # IN
|
||||
const int[::1] X_indices, # IN
|
||||
const int[::1] X_indptr, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # INOUT
|
||||
floating[::1] weight_in_clusters, # INOUT
|
||||
const int[::1] labels # IN
|
||||
):
|
||||
"""Relocate centers which have no sample assigned to them."""
|
||||
cdef:
|
||||
int[::1] empty_clusters = np.where(np.equal(weight_in_clusters, 0))[0].astype(np.int32)
|
||||
int n_empty = empty_clusters.shape[0]
|
||||
|
||||
if n_empty == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
int n_samples = X_indptr.shape[0] - 1
|
||||
int i, j, k
|
||||
|
||||
floating[::1] distances = np.zeros(n_samples, dtype=X_data.base.dtype)
|
||||
floating[::1] centers_squared_norms = row_norms(centers_old, squared=True)
|
||||
|
||||
for i in range(n_samples):
|
||||
j = labels[i]
|
||||
distances[i] = _euclidean_sparse_dense(
|
||||
X_data[X_indptr[i]: X_indptr[i + 1]],
|
||||
X_indices[X_indptr[i]: X_indptr[i + 1]],
|
||||
centers_old[j], centers_squared_norms[j], True)
|
||||
|
||||
if np.max(distances) == 0:
|
||||
# Happens when there are more clusters than non-duplicate samples. Relocating
|
||||
# is pointless in this case.
|
||||
return
|
||||
|
||||
cdef:
|
||||
int[::1] far_from_centers = np.argpartition(distances, -n_empty)[:-n_empty-1:-1].astype(np.int32)
|
||||
|
||||
int new_cluster_id, old_cluster_id, far_idx, idx
|
||||
floating weight
|
||||
|
||||
for idx in range(n_empty):
|
||||
|
||||
new_cluster_id = empty_clusters[idx]
|
||||
|
||||
far_idx = far_from_centers[idx]
|
||||
weight = sample_weight[far_idx]
|
||||
|
||||
old_cluster_id = labels[far_idx]
|
||||
|
||||
for k in range(X_indptr[far_idx], X_indptr[far_idx + 1]):
|
||||
centers_new[old_cluster_id, X_indices[k]] -= X_data[k] * weight
|
||||
centers_new[new_cluster_id, X_indices[k]] = X_data[k] * weight
|
||||
|
||||
weight_in_clusters[new_cluster_id] = weight
|
||||
weight_in_clusters[old_cluster_id] -= weight
|
||||
|
||||
|
||||
cdef void _average_centers(
|
||||
floating[:, ::1] centers, # INOUT
|
||||
const floating[::1] weight_in_clusters # IN
|
||||
):
|
||||
"""Average new centers wrt weights."""
|
||||
cdef:
|
||||
int n_clusters = centers.shape[0]
|
||||
int n_features = centers.shape[1]
|
||||
int j, k
|
||||
floating alpha
|
||||
int argmax_weight = np.argmax(weight_in_clusters)
|
||||
|
||||
for j in range(n_clusters):
|
||||
if weight_in_clusters[j] > 0:
|
||||
alpha = 1.0 / weight_in_clusters[j]
|
||||
for k in range(n_features):
|
||||
centers[j, k] *= alpha
|
||||
else:
|
||||
# For convenience, we avoid setting empty clusters at the origin but place
|
||||
# them at the location of the biggest cluster.
|
||||
for k in range(n_features):
|
||||
centers[j, k] = centers[argmax_weight, k]
|
||||
|
||||
|
||||
cdef void _center_shift(
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
const floating[:, ::1] centers_new, # IN
|
||||
floating[::1] center_shift # OUT
|
||||
):
|
||||
"""Compute shift between old and new centers."""
|
||||
cdef:
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
int j
|
||||
|
||||
for j in range(n_clusters):
|
||||
center_shift[j] = _euclidean_dense_dense(
|
||||
¢ers_new[j, 0], ¢ers_old[j, 0], n_features, False)
|
||||
|
||||
|
||||
def _is_same_clustering(
|
||||
const int[::1] labels1,
|
||||
const int[::1] labels2,
|
||||
n_clusters
|
||||
):
|
||||
"""Check if two arrays of labels are the same up to a permutation of the labels"""
|
||||
cdef int[::1] mapping = np.full(fill_value=-1, shape=(n_clusters,), dtype=np.int32)
|
||||
cdef int i
|
||||
|
||||
for i in range(labels1.shape[0]):
|
||||
if mapping[labels1[i]] == -1:
|
||||
mapping[labels1[i]] = labels2[i]
|
||||
elif mapping[labels1[i]] != labels2[i]:
|
||||
return False
|
||||
return True
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import numpy as np
|
||||
from cython cimport floating
|
||||
from cython.parallel cimport prange
|
||||
from libc.math cimport sqrt
|
||||
|
||||
from ..utils.extmath import row_norms
|
||||
|
||||
|
||||
# Number of samples per data chunk defined as a global constant.
|
||||
CHUNK_SIZE = 256
|
||||
|
||||
|
||||
cdef floating _euclidean_dense_dense(
|
||||
const floating* a, # IN
|
||||
const floating* b, # IN
|
||||
int n_features,
|
||||
bint squared
|
||||
) noexcept nogil:
|
||||
"""Euclidean distance between a dense and b dense"""
|
||||
cdef:
|
||||
int i
|
||||
int n = n_features // 4
|
||||
int rem = n_features % 4
|
||||
floating result = 0
|
||||
|
||||
# We manually unroll the loop for better cache optimization.
|
||||
for i in range(n):
|
||||
result += (
|
||||
(a[0] - b[0]) * (a[0] - b[0]) +
|
||||
(a[1] - b[1]) * (a[1] - b[1]) +
|
||||
(a[2] - b[2]) * (a[2] - b[2]) +
|
||||
(a[3] - b[3]) * (a[3] - b[3])
|
||||
)
|
||||
a += 4
|
||||
b += 4
|
||||
|
||||
for i in range(rem):
|
||||
result += (a[i] - b[i]) * (a[i] - b[i])
|
||||
|
||||
return result if squared else sqrt(result)
|
||||
|
||||
|
||||
def _euclidean_dense_dense_wrapper(
|
||||
const floating[::1] a,
|
||||
const floating[::1] b,
|
||||
bint squared
|
||||
):
|
||||
"""Wrapper of _euclidean_dense_dense for testing purpose"""
|
||||
return _euclidean_dense_dense(&a[0], &b[0], a.shape[0], squared)
|
||||
|
||||
|
||||
cdef floating _euclidean_sparse_dense(
|
||||
const floating[::1] a_data, # IN
|
||||
const int[::1] a_indices, # IN
|
||||
const floating[::1] b, # IN
|
||||
floating b_squared_norm,
|
||||
bint squared
|
||||
) noexcept nogil:
|
||||
"""Euclidean distance between a sparse and b dense"""
|
||||
cdef:
|
||||
int nnz = a_indices.shape[0]
|
||||
int i
|
||||
floating tmp, bi
|
||||
floating result = 0.0
|
||||
|
||||
for i in range(nnz):
|
||||
bi = b[a_indices[i]]
|
||||
tmp = a_data[i] - bi
|
||||
result += tmp * tmp - bi * bi
|
||||
|
||||
result += b_squared_norm
|
||||
|
||||
if result < 0:
|
||||
result = 0.0
|
||||
|
||||
return result if squared else sqrt(result)
|
||||
|
||||
|
||||
def _euclidean_sparse_dense_wrapper(
|
||||
const floating[::1] a_data,
|
||||
const int[::1] a_indices,
|
||||
const floating[::1] b,
|
||||
floating b_squared_norm,
|
||||
bint squared
|
||||
):
|
||||
"""Wrapper of _euclidean_sparse_dense for testing purpose"""
|
||||
return _euclidean_sparse_dense(
|
||||
a_data, a_indices, b, b_squared_norm, squared)
|
||||
|
||||
|
||||
cpdef floating _inertia_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers, # IN
|
||||
const int[::1] labels, # IN
|
||||
int n_threads,
|
||||
int single_label=-1,
|
||||
):
|
||||
"""Compute inertia for dense input data
|
||||
|
||||
Sum of squared distance between each sample and its assigned center.
|
||||
|
||||
If single_label is >= 0, the inertia is computed only for that label.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = X.shape[0]
|
||||
int n_features = X.shape[1]
|
||||
int i, j
|
||||
|
||||
floating sq_dist = 0.0
|
||||
floating inertia = 0.0
|
||||
|
||||
for i in prange(n_samples, nogil=True, num_threads=n_threads,
|
||||
schedule='static'):
|
||||
j = labels[i]
|
||||
if single_label < 0 or single_label == j:
|
||||
sq_dist = _euclidean_dense_dense(&X[i, 0], ¢ers[j, 0],
|
||||
n_features, True)
|
||||
inertia += sq_dist * sample_weight[i]
|
||||
|
||||
return inertia
|
||||
|
||||
|
||||
cpdef floating _inertia_sparse(
|
||||
X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers, # IN
|
||||
const int[::1] labels, # IN
|
||||
int n_threads,
|
||||
int single_label=-1,
|
||||
):
|
||||
"""Compute inertia for sparse input data
|
||||
|
||||
Sum of squared distance between each sample and its assigned center.
|
||||
|
||||
If single_label is >= 0, the inertia is computed only for that label.
|
||||
"""
|
||||
cdef:
|
||||
floating[::1] X_data = X.data
|
||||
int[::1] X_indices = X.indices
|
||||
int[::1] X_indptr = X.indptr
|
||||
|
||||
int n_samples = X.shape[0]
|
||||
int i, j
|
||||
|
||||
floating sq_dist = 0.0
|
||||
floating inertia = 0.0
|
||||
|
||||
floating[::1] centers_squared_norms = row_norms(centers, squared=True)
|
||||
|
||||
for i in prange(n_samples, nogil=True, num_threads=n_threads,
|
||||
schedule='static'):
|
||||
j = labels[i]
|
||||
if single_label < 0 or single_label == j:
|
||||
sq_dist = _euclidean_sparse_dense(
|
||||
X_data[X_indptr[i]: X_indptr[i + 1]],
|
||||
X_indices[X_indptr[i]: X_indptr[i + 1]],
|
||||
centers[j], centers_squared_norms[j], True)
|
||||
inertia += sq_dist * sample_weight[i]
|
||||
|
||||
return inertia
|
||||
|
||||
|
||||
cpdef void _relocate_empty_clusters_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # INOUT
|
||||
floating[::1] weight_in_clusters, # INOUT
|
||||
const int[::1] labels # IN
|
||||
):
|
||||
"""Relocate centers which have no sample assigned to them."""
|
||||
cdef:
|
||||
int[::1] empty_clusters = np.where(np.equal(weight_in_clusters, 0))[0].astype(np.int32)
|
||||
int n_empty = empty_clusters.shape[0]
|
||||
|
||||
if n_empty == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
int n_features = X.shape[1]
|
||||
|
||||
floating[::1] distances = ((np.asarray(X) - np.asarray(centers_old)[labels])**2).sum(axis=1)
|
||||
int[::1] far_from_centers = np.argpartition(distances, -n_empty)[:-n_empty-1:-1].astype(np.int32)
|
||||
|
||||
int new_cluster_id, old_cluster_id, far_idx, idx, k
|
||||
floating weight
|
||||
|
||||
if np.max(distances) == 0:
|
||||
# Happens when there are more clusters than non-duplicate samples. Relocating
|
||||
# is pointless in this case.
|
||||
return
|
||||
|
||||
for idx in range(n_empty):
|
||||
|
||||
new_cluster_id = empty_clusters[idx]
|
||||
|
||||
far_idx = far_from_centers[idx]
|
||||
weight = sample_weight[far_idx]
|
||||
|
||||
old_cluster_id = labels[far_idx]
|
||||
|
||||
for k in range(n_features):
|
||||
centers_new[old_cluster_id, k] -= X[far_idx, k] * weight
|
||||
centers_new[new_cluster_id, k] = X[far_idx, k] * weight
|
||||
|
||||
weight_in_clusters[new_cluster_id] = weight
|
||||
weight_in_clusters[old_cluster_id] -= weight
|
||||
|
||||
|
||||
cpdef void _relocate_empty_clusters_sparse(
|
||||
const floating[::1] X_data, # IN
|
||||
const int[::1] X_indices, # IN
|
||||
const int[::1] X_indptr, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # INOUT
|
||||
floating[::1] weight_in_clusters, # INOUT
|
||||
const int[::1] labels # IN
|
||||
):
|
||||
"""Relocate centers which have no sample assigned to them."""
|
||||
cdef:
|
||||
int[::1] empty_clusters = np.where(np.equal(weight_in_clusters, 0))[0].astype(np.int32)
|
||||
int n_empty = empty_clusters.shape[0]
|
||||
|
||||
if n_empty == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
int n_samples = X_indptr.shape[0] - 1
|
||||
int i, j, k
|
||||
|
||||
floating[::1] distances = np.zeros(n_samples, dtype=X_data.base.dtype)
|
||||
floating[::1] centers_squared_norms = row_norms(centers_old, squared=True)
|
||||
|
||||
for i in range(n_samples):
|
||||
j = labels[i]
|
||||
distances[i] = _euclidean_sparse_dense(
|
||||
X_data[X_indptr[i]: X_indptr[i + 1]],
|
||||
X_indices[X_indptr[i]: X_indptr[i + 1]],
|
||||
centers_old[j], centers_squared_norms[j], True)
|
||||
|
||||
if np.max(distances) == 0:
|
||||
# Happens when there are more clusters than non-duplicate samples. Relocating
|
||||
# is pointless in this case.
|
||||
return
|
||||
|
||||
cdef:
|
||||
int[::1] far_from_centers = np.argpartition(distances, -n_empty)[:-n_empty-1:-1].astype(np.int32)
|
||||
|
||||
int new_cluster_id, old_cluster_id, far_idx, idx
|
||||
floating weight
|
||||
|
||||
for idx in range(n_empty):
|
||||
|
||||
new_cluster_id = empty_clusters[idx]
|
||||
|
||||
far_idx = far_from_centers[idx]
|
||||
weight = sample_weight[far_idx]
|
||||
|
||||
old_cluster_id = labels[far_idx]
|
||||
|
||||
for k in range(X_indptr[far_idx], X_indptr[far_idx + 1]):
|
||||
centers_new[old_cluster_id, X_indices[k]] -= X_data[k] * weight
|
||||
centers_new[new_cluster_id, X_indices[k]] = X_data[k] * weight
|
||||
|
||||
weight_in_clusters[new_cluster_id] = weight
|
||||
weight_in_clusters[old_cluster_id] -= weight
|
||||
|
||||
|
||||
cdef void _average_centers(
|
||||
floating[:, ::1] centers, # INOUT
|
||||
const floating[::1] weight_in_clusters # IN
|
||||
):
|
||||
"""Average new centers wrt weights."""
|
||||
cdef:
|
||||
int n_clusters = centers.shape[0]
|
||||
int n_features = centers.shape[1]
|
||||
int j, k
|
||||
floating alpha
|
||||
int argmax_weight = np.argmax(weight_in_clusters)
|
||||
|
||||
for j in range(n_clusters):
|
||||
if weight_in_clusters[j] > 0:
|
||||
alpha = 1.0 / weight_in_clusters[j]
|
||||
for k in range(n_features):
|
||||
centers[j, k] *= alpha
|
||||
else:
|
||||
# For convenience, we avoid setting empty clusters at the origin but place
|
||||
# them at the location of the biggest cluster.
|
||||
for k in range(n_features):
|
||||
centers[j, k] = centers[argmax_weight, k]
|
||||
|
||||
|
||||
cdef void _center_shift(
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
const floating[:, ::1] centers_new, # IN
|
||||
floating[::1] center_shift # OUT
|
||||
):
|
||||
"""Compute shift between old and new centers."""
|
||||
cdef:
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
int j
|
||||
|
||||
for j in range(n_clusters):
|
||||
center_shift[j] = _euclidean_dense_dense(
|
||||
¢ers_new[j, 0], ¢ers_old[j, 0], n_features, False)
|
||||
|
||||
|
||||
def _is_same_clustering(
|
||||
const int[::1] labels1,
|
||||
const int[::1] labels2,
|
||||
n_clusters
|
||||
):
|
||||
"""Check if two arrays of labels are the same up to a permutation of the labels"""
|
||||
cdef int[::1] mapping = np.full(fill_value=-1, shape=(n_clusters,), dtype=np.int32)
|
||||
cdef int i
|
||||
|
||||
for i in range(labels1.shape[0]):
|
||||
if mapping[labels1[i]] == -1:
|
||||
mapping[labels1[i]] = labels2[i]
|
||||
elif mapping[labels1[i]] != labels2[i]:
|
||||
return False
|
||||
return True
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,420 +1,420 @@
|
||||
# Licence: BSD 3 clause
|
||||
|
||||
from cython cimport floating
|
||||
from cython.parallel import prange, parallel
|
||||
from libc.stdlib cimport malloc, calloc, free
|
||||
from libc.string cimport memset
|
||||
from libc.float cimport DBL_MAX, FLT_MAX
|
||||
|
||||
from ..utils._openmp_helpers cimport omp_lock_t
|
||||
from ..utils._openmp_helpers cimport omp_init_lock
|
||||
from ..utils._openmp_helpers cimport omp_destroy_lock
|
||||
from ..utils._openmp_helpers cimport omp_set_lock
|
||||
from ..utils._openmp_helpers cimport omp_unset_lock
|
||||
from ..utils.extmath import row_norms
|
||||
from ..utils._cython_blas cimport _gemm
|
||||
from ..utils._cython_blas cimport RowMajor, Trans, NoTrans
|
||||
from ._k_means_common import CHUNK_SIZE
|
||||
from ._k_means_common cimport _relocate_empty_clusters_dense
|
||||
from ._k_means_common cimport _relocate_empty_clusters_sparse
|
||||
from ._k_means_common cimport _average_centers, _center_shift
|
||||
|
||||
|
||||
def lloyd_iter_chunked_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_in_clusters, # OUT
|
||||
int[::1] labels, # OUT
|
||||
floating[::1] center_shift, # OUT
|
||||
int n_threads,
|
||||
bint update_centers=True):
|
||||
"""Single iteration of K-means lloyd algorithm with dense input.
|
||||
|
||||
Update labels and centers (inplace), for one iteration, distributed
|
||||
over data chunks.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : ndarray of shape (n_samples, n_features), dtype=floating
|
||||
The observations to cluster.
|
||||
|
||||
sample_weight : ndarray of shape (n_samples,), dtype=floating
|
||||
The weights for each observation in X.
|
||||
|
||||
centers_old : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers before previous iteration, placeholder for the centers after
|
||||
previous iteration.
|
||||
|
||||
centers_new : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers after previous iteration, placeholder for the new centers
|
||||
computed during this iteration. `centers_new` can be `None` if
|
||||
`update_centers` is False.
|
||||
|
||||
weight_in_clusters : ndarray of shape (n_clusters,), dtype=floating
|
||||
Placeholder for the sums of the weights of every observation assigned
|
||||
to each center. `weight_in_clusters` can be `None` if `update_centers`
|
||||
is False.
|
||||
|
||||
labels : ndarray of shape (n_samples,), dtype=int
|
||||
labels assignment.
|
||||
|
||||
center_shift : ndarray of shape (n_clusters,), dtype=floating
|
||||
Distance between old and new centers.
|
||||
|
||||
n_threads : int
|
||||
The number of threads to be used by openmp.
|
||||
|
||||
update_centers : bool
|
||||
- If True, the labels and the new centers will be computed, i.e. runs
|
||||
the E-step and the M-step of the algorithm.
|
||||
- If False, only the labels will be computed, i.e runs the E-step of
|
||||
the algorithm. This is useful especially when calling predict on a
|
||||
fitted model.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = X.shape[0]
|
||||
int n_features = X.shape[1]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
|
||||
if n_samples == 0:
|
||||
# An empty array was passed, do nothing and return early (before
|
||||
# attempting to compute n_chunks). This can typically happen when
|
||||
# calling the prediction function of a bisecting k-means model with a
|
||||
# large fraction of outliers.
|
||||
return
|
||||
|
||||
cdef:
|
||||
# hard-coded number of samples per chunk. Appeared to be close to
|
||||
# optimal in all situations.
|
||||
int n_samples_chunk = CHUNK_SIZE if n_samples > CHUNK_SIZE else n_samples
|
||||
int n_chunks = n_samples // n_samples_chunk
|
||||
int n_samples_rem = n_samples % n_samples_chunk
|
||||
int chunk_idx
|
||||
int start, end
|
||||
|
||||
int j, k
|
||||
|
||||
floating[::1] centers_squared_norms = row_norms(centers_old, squared=True)
|
||||
|
||||
floating *centers_new_chunk
|
||||
floating *weight_in_clusters_chunk
|
||||
floating *pairwise_distances_chunk
|
||||
|
||||
omp_lock_t lock
|
||||
|
||||
# count remainder chunk in total number of chunks
|
||||
n_chunks += n_samples != n_chunks * n_samples_chunk
|
||||
|
||||
# number of threads should not be bigger than number of chunks
|
||||
n_threads = min(n_threads, n_chunks)
|
||||
|
||||
if update_centers:
|
||||
memset(¢ers_new[0, 0], 0, n_clusters * n_features * sizeof(floating))
|
||||
memset(&weight_in_clusters[0], 0, n_clusters * sizeof(floating))
|
||||
omp_init_lock(&lock)
|
||||
|
||||
with nogil, parallel(num_threads=n_threads):
|
||||
# thread local buffers
|
||||
centers_new_chunk = <floating*> calloc(n_clusters * n_features, sizeof(floating))
|
||||
weight_in_clusters_chunk = <floating*> calloc(n_clusters, sizeof(floating))
|
||||
pairwise_distances_chunk = <floating*> malloc(n_samples_chunk * n_clusters * sizeof(floating))
|
||||
|
||||
for chunk_idx in prange(n_chunks, schedule='static'):
|
||||
start = chunk_idx * n_samples_chunk
|
||||
if chunk_idx == n_chunks - 1 and n_samples_rem > 0:
|
||||
end = start + n_samples_rem
|
||||
else:
|
||||
end = start + n_samples_chunk
|
||||
|
||||
_update_chunk_dense(
|
||||
X[start: end],
|
||||
sample_weight[start: end],
|
||||
centers_old,
|
||||
centers_squared_norms,
|
||||
labels[start: end],
|
||||
centers_new_chunk,
|
||||
weight_in_clusters_chunk,
|
||||
pairwise_distances_chunk,
|
||||
update_centers)
|
||||
|
||||
# reduction from local buffers.
|
||||
if update_centers:
|
||||
# The lock is necessary to avoid race conditions when aggregating
|
||||
# info from different thread-local buffers.
|
||||
omp_set_lock(&lock)
|
||||
for j in range(n_clusters):
|
||||
weight_in_clusters[j] += weight_in_clusters_chunk[j]
|
||||
for k in range(n_features):
|
||||
centers_new[j, k] += centers_new_chunk[j * n_features + k]
|
||||
|
||||
omp_unset_lock(&lock)
|
||||
|
||||
free(centers_new_chunk)
|
||||
free(weight_in_clusters_chunk)
|
||||
free(pairwise_distances_chunk)
|
||||
|
||||
if update_centers:
|
||||
omp_destroy_lock(&lock)
|
||||
_relocate_empty_clusters_dense(
|
||||
X, sample_weight, centers_old, centers_new, weight_in_clusters, labels
|
||||
)
|
||||
|
||||
_average_centers(centers_new, weight_in_clusters)
|
||||
_center_shift(centers_old, centers_new, center_shift)
|
||||
|
||||
|
||||
cdef void _update_chunk_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
const floating[::1] centers_squared_norms, # IN
|
||||
int[::1] labels, # OUT
|
||||
floating *centers_new, # OUT
|
||||
floating *weight_in_clusters, # OUT
|
||||
floating *pairwise_distances, # OUT
|
||||
bint update_centers) noexcept nogil:
|
||||
"""K-means combined EM step for one dense data chunk.
|
||||
|
||||
Compute the partial contribution of a single data chunk to the labels and
|
||||
centers.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = labels.shape[0]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
|
||||
floating sq_dist, min_sq_dist
|
||||
int i, j, k, label
|
||||
|
||||
# Instead of computing the full pairwise squared distances matrix,
|
||||
# ||X - C||² = ||X||² - 2 X.C^T + ||C||², we only need to store
|
||||
# the - 2 X.C^T + ||C||² term since the argmin for a given sample only
|
||||
# depends on the centers.
|
||||
# pairwise_distances = ||C||²
|
||||
for i in range(n_samples):
|
||||
for j in range(n_clusters):
|
||||
pairwise_distances[i * n_clusters + j] = centers_squared_norms[j]
|
||||
|
||||
# pairwise_distances += -2 * X.dot(C.T)
|
||||
_gemm(RowMajor, NoTrans, Trans, n_samples, n_clusters, n_features,
|
||||
-2.0, &X[0, 0], n_features, ¢ers_old[0, 0], n_features,
|
||||
1.0, pairwise_distances, n_clusters)
|
||||
|
||||
for i in range(n_samples):
|
||||
min_sq_dist = pairwise_distances[i * n_clusters]
|
||||
label = 0
|
||||
for j in range(1, n_clusters):
|
||||
sq_dist = pairwise_distances[i * n_clusters + j]
|
||||
if sq_dist < min_sq_dist:
|
||||
min_sq_dist = sq_dist
|
||||
label = j
|
||||
labels[i] = label
|
||||
|
||||
if update_centers:
|
||||
weight_in_clusters[label] += sample_weight[i]
|
||||
for k in range(n_features):
|
||||
centers_new[label * n_features + k] += X[i, k] * sample_weight[i]
|
||||
|
||||
|
||||
def lloyd_iter_chunked_sparse(
|
||||
X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_in_clusters, # OUT
|
||||
int[::1] labels, # OUT
|
||||
floating[::1] center_shift, # OUT
|
||||
int n_threads,
|
||||
bint update_centers=True):
|
||||
"""Single iteration of K-means lloyd algorithm with sparse input.
|
||||
|
||||
Update labels and centers (inplace), for one iteration, distributed
|
||||
over data chunks.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : sparse matrix of shape (n_samples, n_features), dtype=floating
|
||||
The observations to cluster. Must be in CSR format.
|
||||
|
||||
sample_weight : ndarray of shape (n_samples,), dtype=floating
|
||||
The weights for each observation in X.
|
||||
|
||||
centers_old : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers before previous iteration, placeholder for the centers after
|
||||
previous iteration.
|
||||
|
||||
centers_new : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers after previous iteration, placeholder for the new centers
|
||||
computed during this iteration. `centers_new` can be `None` if
|
||||
`update_centers` is False.
|
||||
|
||||
weight_in_clusters : ndarray of shape (n_clusters,), dtype=floating
|
||||
Placeholder for the sums of the weights of every observation assigned
|
||||
to each center. `weight_in_clusters` can be `None` if `update_centers`
|
||||
is False.
|
||||
|
||||
labels : ndarray of shape (n_samples,), dtype=int
|
||||
labels assignment.
|
||||
|
||||
center_shift : ndarray of shape (n_clusters,), dtype=floating
|
||||
Distance between old and new centers.
|
||||
|
||||
n_threads : int
|
||||
The number of threads to be used by openmp.
|
||||
|
||||
update_centers : bool
|
||||
- If True, the labels and the new centers will be computed, i.e. runs
|
||||
the E-step and the M-step of the algorithm.
|
||||
- If False, only the labels will be computed, i.e runs the E-step of
|
||||
the algorithm. This is useful especially when calling predict on a
|
||||
fitted model.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = X.shape[0]
|
||||
int n_features = X.shape[1]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
|
||||
if n_samples == 0:
|
||||
# An empty array was passed, do nothing and return early (before
|
||||
# attempting to compute n_chunks). This can typically happen when
|
||||
# calling the prediction function of a bisecting k-means model with a
|
||||
# large fraction of outliers.
|
||||
return
|
||||
|
||||
cdef:
|
||||
# Choose same as for dense. Does not have the same impact since with
|
||||
# sparse data the pairwise distances matrix is not precomputed.
|
||||
# However, splitting in chunks is necessary to get parallelism.
|
||||
int n_samples_chunk = CHUNK_SIZE if n_samples > CHUNK_SIZE else n_samples
|
||||
int n_chunks = n_samples // n_samples_chunk
|
||||
int n_samples_rem = n_samples % n_samples_chunk
|
||||
int chunk_idx
|
||||
int start = 0, end = 0
|
||||
|
||||
int j, k
|
||||
|
||||
floating[::1] X_data = X.data
|
||||
int[::1] X_indices = X.indices
|
||||
int[::1] X_indptr = X.indptr
|
||||
|
||||
floating[::1] centers_squared_norms = row_norms(centers_old, squared=True)
|
||||
|
||||
floating *centers_new_chunk
|
||||
floating *weight_in_clusters_chunk
|
||||
|
||||
omp_lock_t lock
|
||||
|
||||
# count remainder chunk in total number of chunks
|
||||
n_chunks += n_samples != n_chunks * n_samples_chunk
|
||||
|
||||
# number of threads should not be bigger than number of chunks
|
||||
n_threads = min(n_threads, n_chunks)
|
||||
|
||||
if update_centers:
|
||||
memset(¢ers_new[0, 0], 0, n_clusters * n_features * sizeof(floating))
|
||||
memset(&weight_in_clusters[0], 0, n_clusters * sizeof(floating))
|
||||
omp_init_lock(&lock)
|
||||
|
||||
with nogil, parallel(num_threads=n_threads):
|
||||
# thread local buffers
|
||||
centers_new_chunk = <floating*> calloc(n_clusters * n_features, sizeof(floating))
|
||||
weight_in_clusters_chunk = <floating*> calloc(n_clusters, sizeof(floating))
|
||||
|
||||
for chunk_idx in prange(n_chunks, schedule='static'):
|
||||
start = chunk_idx * n_samples_chunk
|
||||
if chunk_idx == n_chunks - 1 and n_samples_rem > 0:
|
||||
end = start + n_samples_rem
|
||||
else:
|
||||
end = start + n_samples_chunk
|
||||
|
||||
_update_chunk_sparse(
|
||||
X_data[X_indptr[start]: X_indptr[end]],
|
||||
X_indices[X_indptr[start]: X_indptr[end]],
|
||||
X_indptr[start: end+1],
|
||||
sample_weight[start: end],
|
||||
centers_old,
|
||||
centers_squared_norms,
|
||||
labels[start: end],
|
||||
centers_new_chunk,
|
||||
weight_in_clusters_chunk,
|
||||
update_centers)
|
||||
|
||||
# reduction from local buffers.
|
||||
if update_centers:
|
||||
# The lock is necessary to avoid race conditions when aggregating
|
||||
# info from different thread-local buffers.
|
||||
omp_set_lock(&lock)
|
||||
for j in range(n_clusters):
|
||||
weight_in_clusters[j] += weight_in_clusters_chunk[j]
|
||||
for k in range(n_features):
|
||||
centers_new[j, k] += centers_new_chunk[j * n_features + k]
|
||||
omp_unset_lock(&lock)
|
||||
|
||||
free(centers_new_chunk)
|
||||
free(weight_in_clusters_chunk)
|
||||
|
||||
if update_centers:
|
||||
omp_destroy_lock(&lock)
|
||||
_relocate_empty_clusters_sparse(
|
||||
X_data, X_indices, X_indptr, sample_weight,
|
||||
centers_old, centers_new, weight_in_clusters, labels)
|
||||
|
||||
_average_centers(centers_new, weight_in_clusters)
|
||||
_center_shift(centers_old, centers_new, center_shift)
|
||||
|
||||
|
||||
cdef void _update_chunk_sparse(
|
||||
const floating[::1] X_data, # IN
|
||||
const int[::1] X_indices, # IN
|
||||
const int[::1] X_indptr, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
const floating[::1] centers_squared_norms, # IN
|
||||
int[::1] labels, # OUT
|
||||
floating *centers_new, # OUT
|
||||
floating *weight_in_clusters, # OUT
|
||||
bint update_centers) noexcept nogil:
|
||||
"""K-means combined EM step for one sparse data chunk.
|
||||
|
||||
Compute the partial contribution of a single data chunk to the labels and
|
||||
centers.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = labels.shape[0]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
|
||||
floating sq_dist, min_sq_dist
|
||||
int i, j, k, label
|
||||
floating max_floating = FLT_MAX if floating is float else DBL_MAX
|
||||
int s = X_indptr[0]
|
||||
|
||||
# XXX Precompute the pairwise distances matrix is not worth for sparse
|
||||
# currently. Should be tested when BLAS (sparse x dense) matrix
|
||||
# multiplication is available.
|
||||
for i in range(n_samples):
|
||||
min_sq_dist = max_floating
|
||||
label = 0
|
||||
|
||||
for j in range(n_clusters):
|
||||
sq_dist = 0.0
|
||||
for k in range(X_indptr[i] - s, X_indptr[i + 1] - s):
|
||||
sq_dist += centers_old[j, X_indices[k]] * X_data[k]
|
||||
|
||||
# Instead of computing the full squared distance with each cluster,
|
||||
# ||X - C||² = ||X||² - 2 X.C^T + ||C||², we only need to compute
|
||||
# the - 2 X.C^T + ||C||² term since the argmin for a given sample
|
||||
# only depends on the centers C.
|
||||
sq_dist = centers_squared_norms[j] -2 * sq_dist
|
||||
if sq_dist < min_sq_dist:
|
||||
min_sq_dist = sq_dist
|
||||
label = j
|
||||
|
||||
labels[i] = label
|
||||
|
||||
if update_centers:
|
||||
weight_in_clusters[label] += sample_weight[i]
|
||||
for k in range(X_indptr[i] - s, X_indptr[i + 1] - s):
|
||||
centers_new[label * n_features + X_indices[k]] += X_data[k] * sample_weight[i]
|
||||
# Licence: BSD 3 clause
|
||||
|
||||
from cython cimport floating
|
||||
from cython.parallel import prange, parallel
|
||||
from libc.stdlib cimport malloc, calloc, free
|
||||
from libc.string cimport memset
|
||||
from libc.float cimport DBL_MAX, FLT_MAX
|
||||
|
||||
from ..utils._openmp_helpers cimport omp_lock_t
|
||||
from ..utils._openmp_helpers cimport omp_init_lock
|
||||
from ..utils._openmp_helpers cimport omp_destroy_lock
|
||||
from ..utils._openmp_helpers cimport omp_set_lock
|
||||
from ..utils._openmp_helpers cimport omp_unset_lock
|
||||
from ..utils.extmath import row_norms
|
||||
from ..utils._cython_blas cimport _gemm
|
||||
from ..utils._cython_blas cimport RowMajor, Trans, NoTrans
|
||||
from ._k_means_common import CHUNK_SIZE
|
||||
from ._k_means_common cimport _relocate_empty_clusters_dense
|
||||
from ._k_means_common cimport _relocate_empty_clusters_sparse
|
||||
from ._k_means_common cimport _average_centers, _center_shift
|
||||
|
||||
|
||||
def lloyd_iter_chunked_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_in_clusters, # OUT
|
||||
int[::1] labels, # OUT
|
||||
floating[::1] center_shift, # OUT
|
||||
int n_threads,
|
||||
bint update_centers=True):
|
||||
"""Single iteration of K-means lloyd algorithm with dense input.
|
||||
|
||||
Update labels and centers (inplace), for one iteration, distributed
|
||||
over data chunks.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : ndarray of shape (n_samples, n_features), dtype=floating
|
||||
The observations to cluster.
|
||||
|
||||
sample_weight : ndarray of shape (n_samples,), dtype=floating
|
||||
The weights for each observation in X.
|
||||
|
||||
centers_old : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers before previous iteration, placeholder for the centers after
|
||||
previous iteration.
|
||||
|
||||
centers_new : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers after previous iteration, placeholder for the new centers
|
||||
computed during this iteration. `centers_new` can be `None` if
|
||||
`update_centers` is False.
|
||||
|
||||
weight_in_clusters : ndarray of shape (n_clusters,), dtype=floating
|
||||
Placeholder for the sums of the weights of every observation assigned
|
||||
to each center. `weight_in_clusters` can be `None` if `update_centers`
|
||||
is False.
|
||||
|
||||
labels : ndarray of shape (n_samples,), dtype=int
|
||||
labels assignment.
|
||||
|
||||
center_shift : ndarray of shape (n_clusters,), dtype=floating
|
||||
Distance between old and new centers.
|
||||
|
||||
n_threads : int
|
||||
The number of threads to be used by openmp.
|
||||
|
||||
update_centers : bool
|
||||
- If True, the labels and the new centers will be computed, i.e. runs
|
||||
the E-step and the M-step of the algorithm.
|
||||
- If False, only the labels will be computed, i.e runs the E-step of
|
||||
the algorithm. This is useful especially when calling predict on a
|
||||
fitted model.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = X.shape[0]
|
||||
int n_features = X.shape[1]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
|
||||
if n_samples == 0:
|
||||
# An empty array was passed, do nothing and return early (before
|
||||
# attempting to compute n_chunks). This can typically happen when
|
||||
# calling the prediction function of a bisecting k-means model with a
|
||||
# large fraction of outliers.
|
||||
return
|
||||
|
||||
cdef:
|
||||
# hard-coded number of samples per chunk. Appeared to be close to
|
||||
# optimal in all situations.
|
||||
int n_samples_chunk = CHUNK_SIZE if n_samples > CHUNK_SIZE else n_samples
|
||||
int n_chunks = n_samples // n_samples_chunk
|
||||
int n_samples_rem = n_samples % n_samples_chunk
|
||||
int chunk_idx
|
||||
int start, end
|
||||
|
||||
int j, k
|
||||
|
||||
floating[::1] centers_squared_norms = row_norms(centers_old, squared=True)
|
||||
|
||||
floating *centers_new_chunk
|
||||
floating *weight_in_clusters_chunk
|
||||
floating *pairwise_distances_chunk
|
||||
|
||||
omp_lock_t lock
|
||||
|
||||
# count remainder chunk in total number of chunks
|
||||
n_chunks += n_samples != n_chunks * n_samples_chunk
|
||||
|
||||
# number of threads should not be bigger than number of chunks
|
||||
n_threads = min(n_threads, n_chunks)
|
||||
|
||||
if update_centers:
|
||||
memset(¢ers_new[0, 0], 0, n_clusters * n_features * sizeof(floating))
|
||||
memset(&weight_in_clusters[0], 0, n_clusters * sizeof(floating))
|
||||
omp_init_lock(&lock)
|
||||
|
||||
with nogil, parallel(num_threads=n_threads):
|
||||
# thread local buffers
|
||||
centers_new_chunk = <floating*> calloc(n_clusters * n_features, sizeof(floating))
|
||||
weight_in_clusters_chunk = <floating*> calloc(n_clusters, sizeof(floating))
|
||||
pairwise_distances_chunk = <floating*> malloc(n_samples_chunk * n_clusters * sizeof(floating))
|
||||
|
||||
for chunk_idx in prange(n_chunks, schedule='static'):
|
||||
start = chunk_idx * n_samples_chunk
|
||||
if chunk_idx == n_chunks - 1 and n_samples_rem > 0:
|
||||
end = start + n_samples_rem
|
||||
else:
|
||||
end = start + n_samples_chunk
|
||||
|
||||
_update_chunk_dense(
|
||||
X[start: end],
|
||||
sample_weight[start: end],
|
||||
centers_old,
|
||||
centers_squared_norms,
|
||||
labels[start: end],
|
||||
centers_new_chunk,
|
||||
weight_in_clusters_chunk,
|
||||
pairwise_distances_chunk,
|
||||
update_centers)
|
||||
|
||||
# reduction from local buffers.
|
||||
if update_centers:
|
||||
# The lock is necessary to avoid race conditions when aggregating
|
||||
# info from different thread-local buffers.
|
||||
omp_set_lock(&lock)
|
||||
for j in range(n_clusters):
|
||||
weight_in_clusters[j] += weight_in_clusters_chunk[j]
|
||||
for k in range(n_features):
|
||||
centers_new[j, k] += centers_new_chunk[j * n_features + k]
|
||||
|
||||
omp_unset_lock(&lock)
|
||||
|
||||
free(centers_new_chunk)
|
||||
free(weight_in_clusters_chunk)
|
||||
free(pairwise_distances_chunk)
|
||||
|
||||
if update_centers:
|
||||
omp_destroy_lock(&lock)
|
||||
_relocate_empty_clusters_dense(
|
||||
X, sample_weight, centers_old, centers_new, weight_in_clusters, labels
|
||||
)
|
||||
|
||||
_average_centers(centers_new, weight_in_clusters)
|
||||
_center_shift(centers_old, centers_new, center_shift)
|
||||
|
||||
|
||||
cdef void _update_chunk_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
const floating[::1] centers_squared_norms, # IN
|
||||
int[::1] labels, # OUT
|
||||
floating *centers_new, # OUT
|
||||
floating *weight_in_clusters, # OUT
|
||||
floating *pairwise_distances, # OUT
|
||||
bint update_centers) noexcept nogil:
|
||||
"""K-means combined EM step for one dense data chunk.
|
||||
|
||||
Compute the partial contribution of a single data chunk to the labels and
|
||||
centers.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = labels.shape[0]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
|
||||
floating sq_dist, min_sq_dist
|
||||
int i, j, k, label
|
||||
|
||||
# Instead of computing the full pairwise squared distances matrix,
|
||||
# ||X - C||² = ||X||² - 2 X.C^T + ||C||², we only need to store
|
||||
# the - 2 X.C^T + ||C||² term since the argmin for a given sample only
|
||||
# depends on the centers.
|
||||
# pairwise_distances = ||C||²
|
||||
for i in range(n_samples):
|
||||
for j in range(n_clusters):
|
||||
pairwise_distances[i * n_clusters + j] = centers_squared_norms[j]
|
||||
|
||||
# pairwise_distances += -2 * X.dot(C.T)
|
||||
_gemm(RowMajor, NoTrans, Trans, n_samples, n_clusters, n_features,
|
||||
-2.0, &X[0, 0], n_features, ¢ers_old[0, 0], n_features,
|
||||
1.0, pairwise_distances, n_clusters)
|
||||
|
||||
for i in range(n_samples):
|
||||
min_sq_dist = pairwise_distances[i * n_clusters]
|
||||
label = 0
|
||||
for j in range(1, n_clusters):
|
||||
sq_dist = pairwise_distances[i * n_clusters + j]
|
||||
if sq_dist < min_sq_dist:
|
||||
min_sq_dist = sq_dist
|
||||
label = j
|
||||
labels[i] = label
|
||||
|
||||
if update_centers:
|
||||
weight_in_clusters[label] += sample_weight[i]
|
||||
for k in range(n_features):
|
||||
centers_new[label * n_features + k] += X[i, k] * sample_weight[i]
|
||||
|
||||
|
||||
def lloyd_iter_chunked_sparse(
|
||||
X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_in_clusters, # OUT
|
||||
int[::1] labels, # OUT
|
||||
floating[::1] center_shift, # OUT
|
||||
int n_threads,
|
||||
bint update_centers=True):
|
||||
"""Single iteration of K-means lloyd algorithm with sparse input.
|
||||
|
||||
Update labels and centers (inplace), for one iteration, distributed
|
||||
over data chunks.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : sparse matrix of shape (n_samples, n_features), dtype=floating
|
||||
The observations to cluster. Must be in CSR format.
|
||||
|
||||
sample_weight : ndarray of shape (n_samples,), dtype=floating
|
||||
The weights for each observation in X.
|
||||
|
||||
centers_old : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers before previous iteration, placeholder for the centers after
|
||||
previous iteration.
|
||||
|
||||
centers_new : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers after previous iteration, placeholder for the new centers
|
||||
computed during this iteration. `centers_new` can be `None` if
|
||||
`update_centers` is False.
|
||||
|
||||
weight_in_clusters : ndarray of shape (n_clusters,), dtype=floating
|
||||
Placeholder for the sums of the weights of every observation assigned
|
||||
to each center. `weight_in_clusters` can be `None` if `update_centers`
|
||||
is False.
|
||||
|
||||
labels : ndarray of shape (n_samples,), dtype=int
|
||||
labels assignment.
|
||||
|
||||
center_shift : ndarray of shape (n_clusters,), dtype=floating
|
||||
Distance between old and new centers.
|
||||
|
||||
n_threads : int
|
||||
The number of threads to be used by openmp.
|
||||
|
||||
update_centers : bool
|
||||
- If True, the labels and the new centers will be computed, i.e. runs
|
||||
the E-step and the M-step of the algorithm.
|
||||
- If False, only the labels will be computed, i.e runs the E-step of
|
||||
the algorithm. This is useful especially when calling predict on a
|
||||
fitted model.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = X.shape[0]
|
||||
int n_features = X.shape[1]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
|
||||
if n_samples == 0:
|
||||
# An empty array was passed, do nothing and return early (before
|
||||
# attempting to compute n_chunks). This can typically happen when
|
||||
# calling the prediction function of a bisecting k-means model with a
|
||||
# large fraction of outliers.
|
||||
return
|
||||
|
||||
cdef:
|
||||
# Choose same as for dense. Does not have the same impact since with
|
||||
# sparse data the pairwise distances matrix is not precomputed.
|
||||
# However, splitting in chunks is necessary to get parallelism.
|
||||
int n_samples_chunk = CHUNK_SIZE if n_samples > CHUNK_SIZE else n_samples
|
||||
int n_chunks = n_samples // n_samples_chunk
|
||||
int n_samples_rem = n_samples % n_samples_chunk
|
||||
int chunk_idx
|
||||
int start = 0, end = 0
|
||||
|
||||
int j, k
|
||||
|
||||
floating[::1] X_data = X.data
|
||||
int[::1] X_indices = X.indices
|
||||
int[::1] X_indptr = X.indptr
|
||||
|
||||
floating[::1] centers_squared_norms = row_norms(centers_old, squared=True)
|
||||
|
||||
floating *centers_new_chunk
|
||||
floating *weight_in_clusters_chunk
|
||||
|
||||
omp_lock_t lock
|
||||
|
||||
# count remainder chunk in total number of chunks
|
||||
n_chunks += n_samples != n_chunks * n_samples_chunk
|
||||
|
||||
# number of threads should not be bigger than number of chunks
|
||||
n_threads = min(n_threads, n_chunks)
|
||||
|
||||
if update_centers:
|
||||
memset(¢ers_new[0, 0], 0, n_clusters * n_features * sizeof(floating))
|
||||
memset(&weight_in_clusters[0], 0, n_clusters * sizeof(floating))
|
||||
omp_init_lock(&lock)
|
||||
|
||||
with nogil, parallel(num_threads=n_threads):
|
||||
# thread local buffers
|
||||
centers_new_chunk = <floating*> calloc(n_clusters * n_features, sizeof(floating))
|
||||
weight_in_clusters_chunk = <floating*> calloc(n_clusters, sizeof(floating))
|
||||
|
||||
for chunk_idx in prange(n_chunks, schedule='static'):
|
||||
start = chunk_idx * n_samples_chunk
|
||||
if chunk_idx == n_chunks - 1 and n_samples_rem > 0:
|
||||
end = start + n_samples_rem
|
||||
else:
|
||||
end = start + n_samples_chunk
|
||||
|
||||
_update_chunk_sparse(
|
||||
X_data[X_indptr[start]: X_indptr[end]],
|
||||
X_indices[X_indptr[start]: X_indptr[end]],
|
||||
X_indptr[start: end+1],
|
||||
sample_weight[start: end],
|
||||
centers_old,
|
||||
centers_squared_norms,
|
||||
labels[start: end],
|
||||
centers_new_chunk,
|
||||
weight_in_clusters_chunk,
|
||||
update_centers)
|
||||
|
||||
# reduction from local buffers.
|
||||
if update_centers:
|
||||
# The lock is necessary to avoid race conditions when aggregating
|
||||
# info from different thread-local buffers.
|
||||
omp_set_lock(&lock)
|
||||
for j in range(n_clusters):
|
||||
weight_in_clusters[j] += weight_in_clusters_chunk[j]
|
||||
for k in range(n_features):
|
||||
centers_new[j, k] += centers_new_chunk[j * n_features + k]
|
||||
omp_unset_lock(&lock)
|
||||
|
||||
free(centers_new_chunk)
|
||||
free(weight_in_clusters_chunk)
|
||||
|
||||
if update_centers:
|
||||
omp_destroy_lock(&lock)
|
||||
_relocate_empty_clusters_sparse(
|
||||
X_data, X_indices, X_indptr, sample_weight,
|
||||
centers_old, centers_new, weight_in_clusters, labels)
|
||||
|
||||
_average_centers(centers_new, weight_in_clusters)
|
||||
_center_shift(centers_old, centers_new, center_shift)
|
||||
|
||||
|
||||
cdef void _update_chunk_sparse(
|
||||
const floating[::1] X_data, # IN
|
||||
const int[::1] X_indices, # IN
|
||||
const int[::1] X_indptr, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
const floating[::1] centers_squared_norms, # IN
|
||||
int[::1] labels, # OUT
|
||||
floating *centers_new, # OUT
|
||||
floating *weight_in_clusters, # OUT
|
||||
bint update_centers) noexcept nogil:
|
||||
"""K-means combined EM step for one sparse data chunk.
|
||||
|
||||
Compute the partial contribution of a single data chunk to the labels and
|
||||
centers.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = labels.shape[0]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
|
||||
floating sq_dist, min_sq_dist
|
||||
int i, j, k, label
|
||||
floating max_floating = FLT_MAX if floating is float else DBL_MAX
|
||||
int s = X_indptr[0]
|
||||
|
||||
# XXX Precompute the pairwise distances matrix is not worth for sparse
|
||||
# currently. Should be tested when BLAS (sparse x dense) matrix
|
||||
# multiplication is available.
|
||||
for i in range(n_samples):
|
||||
min_sq_dist = max_floating
|
||||
label = 0
|
||||
|
||||
for j in range(n_clusters):
|
||||
sq_dist = 0.0
|
||||
for k in range(X_indptr[i] - s, X_indptr[i + 1] - s):
|
||||
sq_dist += centers_old[j, X_indices[k]] * X_data[k]
|
||||
|
||||
# Instead of computing the full squared distance with each cluster,
|
||||
# ||X - C||² = ||X||² - 2 X.C^T + ||C||², we only need to compute
|
||||
# the - 2 X.C^T + ||C||² term since the argmin for a given sample
|
||||
# only depends on the centers C.
|
||||
sq_dist = centers_squared_norms[j] -2 * sq_dist
|
||||
if sq_dist < min_sq_dist:
|
||||
min_sq_dist = sq_dist
|
||||
label = j
|
||||
|
||||
labels[i] = label
|
||||
|
||||
if update_centers:
|
||||
weight_in_clusters[label] += sample_weight[i]
|
||||
for k in range(X_indptr[i] - s, X_indptr[i + 1] - s):
|
||||
centers_new[label * n_features + X_indices[k]] += X_data[k] * sample_weight[i]
|
||||
|
||||
+218
-218
@@ -1,218 +1,218 @@
|
||||
from cython cimport floating
|
||||
from cython.parallel cimport parallel, prange
|
||||
from libc.stdlib cimport malloc, free
|
||||
|
||||
|
||||
def _minibatch_update_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_sums, # INOUT
|
||||
const int[::1] labels, # IN
|
||||
int n_threads):
|
||||
"""Update of the centers for dense MiniBatchKMeans.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : ndarray of shape (n_samples, n_features), dtype=floating
|
||||
The observations to cluster.
|
||||
|
||||
sample_weight : ndarray of shape (n_samples,), dtype=floating
|
||||
The weights for each observation in X.
|
||||
|
||||
centers_old : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers before previous iteration, placeholder for the centers after
|
||||
previous iteration.
|
||||
|
||||
centers_new : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers after previous iteration, placeholder for the new centers
|
||||
computed during this iteration.
|
||||
|
||||
weight_sums : ndarray of shape (n_clusters,), dtype=floating
|
||||
Current sums of the accumulated weights for each center.
|
||||
|
||||
labels : ndarray of shape (n_samples,), dtype=int
|
||||
labels assignment.
|
||||
|
||||
n_threads : int
|
||||
The number of threads to be used by openmp.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = X.shape[0]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int cluster_idx
|
||||
|
||||
int *indices
|
||||
|
||||
with nogil, parallel(num_threads=n_threads):
|
||||
indices = <int*> malloc(n_samples * sizeof(int))
|
||||
|
||||
for cluster_idx in prange(n_clusters, schedule="static"):
|
||||
update_center_dense(cluster_idx, X, sample_weight,
|
||||
centers_old, centers_new, weight_sums, labels,
|
||||
indices)
|
||||
|
||||
free(indices)
|
||||
|
||||
|
||||
cdef void update_center_dense(
|
||||
int cluster_idx,
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_sums, # INOUT
|
||||
const int[::1] labels, # IN
|
||||
int *indices) noexcept nogil: # TMP
|
||||
"""Update of a single center for dense MinibatchKMeans"""
|
||||
cdef:
|
||||
int n_samples = sample_weight.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
floating alpha
|
||||
int n_indices
|
||||
int k, sample_idx, feature_idx
|
||||
|
||||
floating wsum = 0
|
||||
|
||||
# indices = np.where(labels == cluster_idx)[0]
|
||||
k = 0
|
||||
for sample_idx in range(n_samples):
|
||||
if labels[sample_idx] == cluster_idx:
|
||||
indices[k] = sample_idx
|
||||
wsum += sample_weight[sample_idx]
|
||||
k += 1
|
||||
n_indices = k
|
||||
|
||||
if wsum > 0:
|
||||
# Undo the previous count-based scaling for this cluster center
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] = centers_old[cluster_idx, feature_idx] * weight_sums[cluster_idx]
|
||||
|
||||
# Update cluster with new point members
|
||||
for k in range(n_indices):
|
||||
sample_idx = indices[k]
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] += X[sample_idx, feature_idx] * sample_weight[sample_idx]
|
||||
|
||||
# Update the count statistics for this center
|
||||
weight_sums[cluster_idx] += wsum
|
||||
|
||||
# Rescale to compute mean of all points (old and new)
|
||||
alpha = 1 / weight_sums[cluster_idx]
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] *= alpha
|
||||
else:
|
||||
# No sample was assigned to this cluster in this batch of data
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] = centers_old[cluster_idx, feature_idx]
|
||||
|
||||
|
||||
def _minibatch_update_sparse(
|
||||
X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_sums, # INOUT
|
||||
const int[::1] labels, # IN
|
||||
int n_threads):
|
||||
"""Update of the centers for sparse MiniBatchKMeans.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : sparse matrix of shape (n_samples, n_features), dtype=floating
|
||||
The observations to cluster. Must be in CSR format.
|
||||
|
||||
sample_weight : ndarray of shape (n_samples,), dtype=floating
|
||||
The weights for each observation in X.
|
||||
|
||||
centers_old : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers before previous iteration, placeholder for the centers after
|
||||
previous iteration.
|
||||
|
||||
centers_new : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers after previous iteration, placeholder for the new centers
|
||||
computed during this iteration.
|
||||
|
||||
weight_sums : ndarray of shape (n_clusters,), dtype=floating
|
||||
Current sums of the accumulated weights for each center.
|
||||
|
||||
labels : ndarray of shape (n_samples,), dtype=int
|
||||
labels assignment.
|
||||
|
||||
n_threads : int
|
||||
The number of threads to be used by openmp.
|
||||
"""
|
||||
cdef:
|
||||
floating[::1] X_data = X.data
|
||||
int[::1] X_indices = X.indices
|
||||
int[::1] X_indptr = X.indptr
|
||||
int n_samples = X.shape[0]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int cluster_idx
|
||||
|
||||
int *indices
|
||||
|
||||
with nogil, parallel(num_threads=n_threads):
|
||||
indices = <int*> malloc(n_samples * sizeof(int))
|
||||
|
||||
for cluster_idx in prange(n_clusters, schedule="static"):
|
||||
update_center_sparse(cluster_idx, X_data, X_indices, X_indptr,
|
||||
sample_weight, centers_old, centers_new,
|
||||
weight_sums, labels, indices)
|
||||
|
||||
free(indices)
|
||||
|
||||
|
||||
cdef void update_center_sparse(
|
||||
int cluster_idx,
|
||||
const floating[::1] X_data, # IN
|
||||
const int[::1] X_indices, # IN
|
||||
const int[::1] X_indptr, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_sums, # INOUT
|
||||
const int[::1] labels, # IN
|
||||
int *indices) noexcept nogil: # TMP
|
||||
"""Update of a single center for sparse MinibatchKMeans"""
|
||||
cdef:
|
||||
int n_samples = sample_weight.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
floating alpha
|
||||
int n_indices
|
||||
int k, sample_idx, feature_idx
|
||||
|
||||
floating wsum = 0
|
||||
|
||||
# indices = np.where(labels == cluster_idx)[0]
|
||||
k = 0
|
||||
for sample_idx in range(n_samples):
|
||||
if labels[sample_idx] == cluster_idx:
|
||||
indices[k] = sample_idx
|
||||
wsum += sample_weight[sample_idx]
|
||||
k += 1
|
||||
n_indices = k
|
||||
|
||||
if wsum > 0:
|
||||
# Undo the previous count-based scaling for this cluster center:
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] = centers_old[cluster_idx, feature_idx] * weight_sums[cluster_idx]
|
||||
|
||||
# Update cluster with new point members
|
||||
for k in range(n_indices):
|
||||
sample_idx = indices[k]
|
||||
for feature_idx in range(X_indptr[sample_idx], X_indptr[sample_idx + 1]):
|
||||
centers_new[cluster_idx, X_indices[feature_idx]] += X_data[feature_idx] * sample_weight[sample_idx]
|
||||
|
||||
# Update the count statistics for this center
|
||||
weight_sums[cluster_idx] += wsum
|
||||
|
||||
# Rescale to compute mean of all points (old and new)
|
||||
alpha = 1 / weight_sums[cluster_idx]
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] *= alpha
|
||||
else:
|
||||
# No sample was assigned to this cluster in this batch of data
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] = centers_old[cluster_idx, feature_idx]
|
||||
from cython cimport floating
|
||||
from cython.parallel cimport parallel, prange
|
||||
from libc.stdlib cimport malloc, free
|
||||
|
||||
|
||||
def _minibatch_update_dense(
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_sums, # INOUT
|
||||
const int[::1] labels, # IN
|
||||
int n_threads):
|
||||
"""Update of the centers for dense MiniBatchKMeans.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : ndarray of shape (n_samples, n_features), dtype=floating
|
||||
The observations to cluster.
|
||||
|
||||
sample_weight : ndarray of shape (n_samples,), dtype=floating
|
||||
The weights for each observation in X.
|
||||
|
||||
centers_old : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers before previous iteration, placeholder for the centers after
|
||||
previous iteration.
|
||||
|
||||
centers_new : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers after previous iteration, placeholder for the new centers
|
||||
computed during this iteration.
|
||||
|
||||
weight_sums : ndarray of shape (n_clusters,), dtype=floating
|
||||
Current sums of the accumulated weights for each center.
|
||||
|
||||
labels : ndarray of shape (n_samples,), dtype=int
|
||||
labels assignment.
|
||||
|
||||
n_threads : int
|
||||
The number of threads to be used by openmp.
|
||||
"""
|
||||
cdef:
|
||||
int n_samples = X.shape[0]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int cluster_idx
|
||||
|
||||
int *indices
|
||||
|
||||
with nogil, parallel(num_threads=n_threads):
|
||||
indices = <int*> malloc(n_samples * sizeof(int))
|
||||
|
||||
for cluster_idx in prange(n_clusters, schedule="static"):
|
||||
update_center_dense(cluster_idx, X, sample_weight,
|
||||
centers_old, centers_new, weight_sums, labels,
|
||||
indices)
|
||||
|
||||
free(indices)
|
||||
|
||||
|
||||
cdef void update_center_dense(
|
||||
int cluster_idx,
|
||||
const floating[:, ::1] X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_sums, # INOUT
|
||||
const int[::1] labels, # IN
|
||||
int *indices) noexcept nogil: # TMP
|
||||
"""Update of a single center for dense MinibatchKMeans"""
|
||||
cdef:
|
||||
int n_samples = sample_weight.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
floating alpha
|
||||
int n_indices
|
||||
int k, sample_idx, feature_idx
|
||||
|
||||
floating wsum = 0
|
||||
|
||||
# indices = np.where(labels == cluster_idx)[0]
|
||||
k = 0
|
||||
for sample_idx in range(n_samples):
|
||||
if labels[sample_idx] == cluster_idx:
|
||||
indices[k] = sample_idx
|
||||
wsum += sample_weight[sample_idx]
|
||||
k += 1
|
||||
n_indices = k
|
||||
|
||||
if wsum > 0:
|
||||
# Undo the previous count-based scaling for this cluster center
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] = centers_old[cluster_idx, feature_idx] * weight_sums[cluster_idx]
|
||||
|
||||
# Update cluster with new point members
|
||||
for k in range(n_indices):
|
||||
sample_idx = indices[k]
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] += X[sample_idx, feature_idx] * sample_weight[sample_idx]
|
||||
|
||||
# Update the count statistics for this center
|
||||
weight_sums[cluster_idx] += wsum
|
||||
|
||||
# Rescale to compute mean of all points (old and new)
|
||||
alpha = 1 / weight_sums[cluster_idx]
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] *= alpha
|
||||
else:
|
||||
# No sample was assigned to this cluster in this batch of data
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] = centers_old[cluster_idx, feature_idx]
|
||||
|
||||
|
||||
def _minibatch_update_sparse(
|
||||
X, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_sums, # INOUT
|
||||
const int[::1] labels, # IN
|
||||
int n_threads):
|
||||
"""Update of the centers for sparse MiniBatchKMeans.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : sparse matrix of shape (n_samples, n_features), dtype=floating
|
||||
The observations to cluster. Must be in CSR format.
|
||||
|
||||
sample_weight : ndarray of shape (n_samples,), dtype=floating
|
||||
The weights for each observation in X.
|
||||
|
||||
centers_old : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers before previous iteration, placeholder for the centers after
|
||||
previous iteration.
|
||||
|
||||
centers_new : ndarray of shape (n_clusters, n_features), dtype=floating
|
||||
Centers after previous iteration, placeholder for the new centers
|
||||
computed during this iteration.
|
||||
|
||||
weight_sums : ndarray of shape (n_clusters,), dtype=floating
|
||||
Current sums of the accumulated weights for each center.
|
||||
|
||||
labels : ndarray of shape (n_samples,), dtype=int
|
||||
labels assignment.
|
||||
|
||||
n_threads : int
|
||||
The number of threads to be used by openmp.
|
||||
"""
|
||||
cdef:
|
||||
floating[::1] X_data = X.data
|
||||
int[::1] X_indices = X.indices
|
||||
int[::1] X_indptr = X.indptr
|
||||
int n_samples = X.shape[0]
|
||||
int n_clusters = centers_old.shape[0]
|
||||
int cluster_idx
|
||||
|
||||
int *indices
|
||||
|
||||
with nogil, parallel(num_threads=n_threads):
|
||||
indices = <int*> malloc(n_samples * sizeof(int))
|
||||
|
||||
for cluster_idx in prange(n_clusters, schedule="static"):
|
||||
update_center_sparse(cluster_idx, X_data, X_indices, X_indptr,
|
||||
sample_weight, centers_old, centers_new,
|
||||
weight_sums, labels, indices)
|
||||
|
||||
free(indices)
|
||||
|
||||
|
||||
cdef void update_center_sparse(
|
||||
int cluster_idx,
|
||||
const floating[::1] X_data, # IN
|
||||
const int[::1] X_indices, # IN
|
||||
const int[::1] X_indptr, # IN
|
||||
const floating[::1] sample_weight, # IN
|
||||
const floating[:, ::1] centers_old, # IN
|
||||
floating[:, ::1] centers_new, # OUT
|
||||
floating[::1] weight_sums, # INOUT
|
||||
const int[::1] labels, # IN
|
||||
int *indices) noexcept nogil: # TMP
|
||||
"""Update of a single center for sparse MinibatchKMeans"""
|
||||
cdef:
|
||||
int n_samples = sample_weight.shape[0]
|
||||
int n_features = centers_old.shape[1]
|
||||
floating alpha
|
||||
int n_indices
|
||||
int k, sample_idx, feature_idx
|
||||
|
||||
floating wsum = 0
|
||||
|
||||
# indices = np.where(labels == cluster_idx)[0]
|
||||
k = 0
|
||||
for sample_idx in range(n_samples):
|
||||
if labels[sample_idx] == cluster_idx:
|
||||
indices[k] = sample_idx
|
||||
wsum += sample_weight[sample_idx]
|
||||
k += 1
|
||||
n_indices = k
|
||||
|
||||
if wsum > 0:
|
||||
# Undo the previous count-based scaling for this cluster center:
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] = centers_old[cluster_idx, feature_idx] * weight_sums[cluster_idx]
|
||||
|
||||
# Update cluster with new point members
|
||||
for k in range(n_indices):
|
||||
sample_idx = indices[k]
|
||||
for feature_idx in range(X_indptr[sample_idx], X_indptr[sample_idx + 1]):
|
||||
centers_new[cluster_idx, X_indices[feature_idx]] += X_data[feature_idx] * sample_weight[sample_idx]
|
||||
|
||||
# Update the count statistics for this center
|
||||
weight_sums[cluster_idx] += wsum
|
||||
|
||||
# Rescale to compute mean of all points (old and new)
|
||||
alpha = 1 / weight_sums[cluster_idx]
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] *= alpha
|
||||
else:
|
||||
# No sample was assigned to this cluster in this batch of data
|
||||
for feature_idx in range(n_features):
|
||||
centers_new[cluster_idx, feature_idx] = centers_old[cluster_idx, feature_idx]
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
cluster_extension_metadata = {
|
||||
'_dbscan_inner':
|
||||
{'sources': [cython_gen_cpp.process('_dbscan_inner.pyx')]},
|
||||
'_hierarchical_fast':
|
||||
{'sources': [cython_gen_cpp.process('_hierarchical_fast.pyx'), metrics_cython_tree]},
|
||||
'_k_means_common':
|
||||
{'sources': [cython_gen.process('_k_means_common.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_k_means_lloyd':
|
||||
{'sources': [cython_gen.process('_k_means_lloyd.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_k_means_elkan':
|
||||
{'sources': [cython_gen.process('_k_means_elkan.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_k_means_minibatch':
|
||||
{'sources': [cython_gen.process('_k_means_minibatch.pyx')], 'dependencies': [openmp_dep]},
|
||||
}
|
||||
|
||||
foreach ext_name, ext_dict : cluster_extension_metadata
|
||||
py.extension_module(
|
||||
ext_name,
|
||||
[ext_dict.get('sources'), utils_cython_tree],
|
||||
dependencies: [np_dep] + ext_dict.get('dependencies', []),
|
||||
subdir: 'sklearn/cluster',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
|
||||
subdir('_hdbscan')
|
||||
cluster_extension_metadata = {
|
||||
'_dbscan_inner':
|
||||
{'sources': [cython_gen_cpp.process('_dbscan_inner.pyx')]},
|
||||
'_hierarchical_fast':
|
||||
{'sources': [cython_gen_cpp.process('_hierarchical_fast.pyx'), metrics_cython_tree]},
|
||||
'_k_means_common':
|
||||
{'sources': [cython_gen.process('_k_means_common.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_k_means_lloyd':
|
||||
{'sources': [cython_gen.process('_k_means_lloyd.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_k_means_elkan':
|
||||
{'sources': [cython_gen.process('_k_means_elkan.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_k_means_minibatch':
|
||||
{'sources': [cython_gen.process('_k_means_minibatch.pyx')], 'dependencies': [openmp_dep]},
|
||||
}
|
||||
|
||||
foreach ext_name, ext_dict : cluster_extension_metadata
|
||||
py.extension_module(
|
||||
ext_name,
|
||||
[ext_dict.get('sources'), utils_cython_tree],
|
||||
dependencies: [np_dep] + ext_dict.get('dependencies', []),
|
||||
subdir: 'sklearn/cluster',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
|
||||
subdir('_hdbscan')
|
||||
|
||||
+252
-252
@@ -1,252 +1,252 @@
|
||||
# Optimized inner loop of load_svmlight_file.
|
||||
#
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import array
|
||||
from cpython cimport array
|
||||
cimport cython
|
||||
from libc.string cimport strchr
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
cdef bytes COMMA = u','.encode('ascii')
|
||||
cdef bytes COLON = u':'.encode('ascii')
|
||||
|
||||
|
||||
def _load_svmlight_file(f, dtype, bint multilabel, bint zero_based,
|
||||
bint query_id, long long offset, long long length):
|
||||
cdef array.array data, indices, indptr
|
||||
cdef bytes line
|
||||
cdef char *hash_ptr
|
||||
cdef char *line_cstr
|
||||
cdef int idx, prev_idx
|
||||
cdef Py_ssize_t i
|
||||
cdef bytes qid_prefix = b'qid'
|
||||
cdef Py_ssize_t n_features
|
||||
cdef long long offset_max = offset + length if length > 0 else -1
|
||||
|
||||
# Special-case float32 but use float64 for everything else;
|
||||
# the Python code will do further conversions.
|
||||
if dtype == np.float32:
|
||||
data = array.array("f")
|
||||
else:
|
||||
dtype = np.float64
|
||||
data = array.array("d")
|
||||
|
||||
indices = array.array("q")
|
||||
indptr = array.array("q", [0])
|
||||
query = np.arange(0, dtype=np.int64)
|
||||
|
||||
if multilabel:
|
||||
labels = []
|
||||
else:
|
||||
labels = array.array("d")
|
||||
|
||||
if offset > 0:
|
||||
f.seek(offset)
|
||||
# drop the current line that might be truncated and is to be
|
||||
# fetched by another call
|
||||
f.readline()
|
||||
|
||||
for line in f:
|
||||
# skip comments
|
||||
line_cstr = line
|
||||
hash_ptr = strchr(line_cstr, 35) # ASCII value of '#' is 35
|
||||
if hash_ptr != NULL:
|
||||
line = line[:hash_ptr - line_cstr]
|
||||
|
||||
line_parts = line.split()
|
||||
if len(line_parts) == 0:
|
||||
continue
|
||||
|
||||
target, features = line_parts[0], line_parts[1:]
|
||||
if multilabel:
|
||||
if COLON in target:
|
||||
target, features = [], line_parts[0:]
|
||||
else:
|
||||
target = [float(y) for y in target.split(COMMA)]
|
||||
target.sort()
|
||||
labels.append(tuple(target))
|
||||
else:
|
||||
array.resize_smart(labels, len(labels) + 1)
|
||||
labels[len(labels) - 1] = float(target)
|
||||
|
||||
prev_idx = -1
|
||||
n_features = len(features)
|
||||
if n_features and features[0].startswith(qid_prefix):
|
||||
_, value = features[0].split(COLON, 1)
|
||||
if query_id:
|
||||
query.resize(len(query) + 1)
|
||||
query[len(query) - 1] = np.int64(value)
|
||||
features.pop(0)
|
||||
n_features -= 1
|
||||
|
||||
for i in range(0, n_features):
|
||||
idx_s, value = features[i].split(COLON, 1)
|
||||
idx = int(idx_s)
|
||||
if idx < 0 or not zero_based and idx == 0:
|
||||
raise ValueError(
|
||||
"Invalid index %d in SVMlight/LibSVM data file." % idx)
|
||||
if idx <= prev_idx:
|
||||
raise ValueError("Feature indices in SVMlight/LibSVM data "
|
||||
"file should be sorted and unique.")
|
||||
|
||||
array.resize_smart(indices, len(indices) + 1)
|
||||
indices[len(indices) - 1] = idx
|
||||
|
||||
array.resize_smart(data, len(data) + 1)
|
||||
data[len(data) - 1] = float(value)
|
||||
|
||||
prev_idx = idx
|
||||
|
||||
# increment index pointer array size
|
||||
array.resize_smart(indptr, len(indptr) + 1)
|
||||
indptr[len(indptr) - 1] = len(data)
|
||||
|
||||
if offset_max != -1 and f.tell() > offset_max:
|
||||
# Stop here and let another call deal with the following.
|
||||
break
|
||||
|
||||
return (dtype, data, indices, indptr, labels, query)
|
||||
|
||||
|
||||
# Two fused types are defined to be able to
|
||||
# use all possible combinations of parameters.
|
||||
ctypedef fused int_or_float:
|
||||
cython.integral
|
||||
cython.floating
|
||||
signed long long
|
||||
|
||||
ctypedef fused double_or_longlong:
|
||||
double
|
||||
signed long long
|
||||
|
||||
ctypedef fused int_or_longlong:
|
||||
cython.integral
|
||||
signed long long
|
||||
|
||||
|
||||
def get_dense_row_string(
|
||||
const int_or_float[:, :] X,
|
||||
Py_ssize_t[:] x_inds,
|
||||
double_or_longlong[:] x_vals,
|
||||
Py_ssize_t row,
|
||||
str value_pattern,
|
||||
bint one_based,
|
||||
):
|
||||
cdef:
|
||||
Py_ssize_t row_length = X.shape[1]
|
||||
Py_ssize_t x_nz_used = 0
|
||||
Py_ssize_t k
|
||||
int_or_float val
|
||||
|
||||
for k in range(row_length):
|
||||
val = X[row, k]
|
||||
if val == 0:
|
||||
continue
|
||||
x_inds[x_nz_used] = k
|
||||
x_vals[x_nz_used] = <double_or_longlong> val
|
||||
x_nz_used += 1
|
||||
|
||||
reprs = [
|
||||
value_pattern % (x_inds[i] + one_based, x_vals[i])
|
||||
for i in range(x_nz_used)
|
||||
]
|
||||
|
||||
return " ".join(reprs)
|
||||
|
||||
|
||||
def get_sparse_row_string(
|
||||
int_or_float[:] X_data,
|
||||
int[:] X_indptr,
|
||||
int[:] X_indices,
|
||||
Py_ssize_t row,
|
||||
str value_pattern,
|
||||
bint one_based,
|
||||
):
|
||||
cdef:
|
||||
Py_ssize_t row_start = X_indptr[row]
|
||||
Py_ssize_t row_end = X_indptr[row+1]
|
||||
|
||||
reprs = [
|
||||
value_pattern % (X_indices[i] + one_based, X_data[i])
|
||||
for i in range(row_start, row_end)
|
||||
]
|
||||
|
||||
return " ".join(reprs)
|
||||
|
||||
|
||||
def _dump_svmlight_file(
|
||||
X,
|
||||
y,
|
||||
f,
|
||||
bint multilabel,
|
||||
bint one_based,
|
||||
int_or_longlong[:] query_id,
|
||||
bint X_is_sp,
|
||||
bint y_is_sp,
|
||||
):
|
||||
cdef bint X_is_integral
|
||||
cdef bint query_id_is_not_empty = query_id.size > 0
|
||||
X_is_integral = X.dtype.kind == "i"
|
||||
if X_is_integral:
|
||||
value_pattern = "%d:%d"
|
||||
else:
|
||||
value_pattern = "%d:%.16g"
|
||||
if y.dtype.kind == "i":
|
||||
label_pattern = "%d"
|
||||
else:
|
||||
label_pattern = "%.16g"
|
||||
|
||||
line_pattern = "%s"
|
||||
if query_id_is_not_empty:
|
||||
line_pattern += " qid:%d"
|
||||
line_pattern += " %s\n"
|
||||
|
||||
cdef:
|
||||
Py_ssize_t num_labels = y.shape[1]
|
||||
Py_ssize_t x_len = X.shape[0]
|
||||
Py_ssize_t row_length = X.shape[1]
|
||||
Py_ssize_t i
|
||||
Py_ssize_t j
|
||||
Py_ssize_t col_start
|
||||
Py_ssize_t col_end
|
||||
Py_ssize_t[:] x_inds = np.empty(row_length, dtype=np.intp)
|
||||
signed long long[:] x_vals_int
|
||||
double[:] x_vals_float
|
||||
|
||||
if not X_is_sp:
|
||||
if X_is_integral:
|
||||
x_vals_int = np.zeros(row_length, dtype=np.longlong)
|
||||
else:
|
||||
x_vals_float = np.zeros(row_length, dtype=np.float64)
|
||||
|
||||
for i in range(x_len):
|
||||
if not X_is_sp:
|
||||
if X_is_integral:
|
||||
s = get_dense_row_string(X, x_inds, x_vals_int, i, value_pattern, one_based)
|
||||
else:
|
||||
s = get_dense_row_string(X, x_inds, x_vals_float, i, value_pattern, one_based)
|
||||
else:
|
||||
s = get_sparse_row_string(X.data, X.indptr, X.indices, i, value_pattern, one_based)
|
||||
if multilabel:
|
||||
if y_is_sp:
|
||||
col_start = y.indptr[i]
|
||||
col_end = y.indptr[i+1]
|
||||
labels_str = ','.join(tuple(label_pattern % y.indices[j] for j in range(col_start, col_end) if y.data[j] != 0))
|
||||
else:
|
||||
labels_str = ','.join(label_pattern % j for j in range(num_labels) if y[i, j] != 0)
|
||||
else:
|
||||
if y_is_sp:
|
||||
labels_str = label_pattern % y.data[i]
|
||||
else:
|
||||
labels_str = label_pattern % y[i, 0]
|
||||
|
||||
if query_id_is_not_empty:
|
||||
feat = (labels_str, query_id[i], s)
|
||||
else:
|
||||
feat = (labels_str, s)
|
||||
|
||||
f.write((line_pattern % feat).encode("utf-8"))
|
||||
# Optimized inner loop of load_svmlight_file.
|
||||
#
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import array
|
||||
from cpython cimport array
|
||||
cimport cython
|
||||
from libc.string cimport strchr
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
cdef bytes COMMA = u','.encode('ascii')
|
||||
cdef bytes COLON = u':'.encode('ascii')
|
||||
|
||||
|
||||
def _load_svmlight_file(f, dtype, bint multilabel, bint zero_based,
|
||||
bint query_id, long long offset, long long length):
|
||||
cdef array.array data, indices, indptr
|
||||
cdef bytes line
|
||||
cdef char *hash_ptr
|
||||
cdef char *line_cstr
|
||||
cdef int idx, prev_idx
|
||||
cdef Py_ssize_t i
|
||||
cdef bytes qid_prefix = b'qid'
|
||||
cdef Py_ssize_t n_features
|
||||
cdef long long offset_max = offset + length if length > 0 else -1
|
||||
|
||||
# Special-case float32 but use float64 for everything else;
|
||||
# the Python code will do further conversions.
|
||||
if dtype == np.float32:
|
||||
data = array.array("f")
|
||||
else:
|
||||
dtype = np.float64
|
||||
data = array.array("d")
|
||||
|
||||
indices = array.array("q")
|
||||
indptr = array.array("q", [0])
|
||||
query = np.arange(0, dtype=np.int64)
|
||||
|
||||
if multilabel:
|
||||
labels = []
|
||||
else:
|
||||
labels = array.array("d")
|
||||
|
||||
if offset > 0:
|
||||
f.seek(offset)
|
||||
# drop the current line that might be truncated and is to be
|
||||
# fetched by another call
|
||||
f.readline()
|
||||
|
||||
for line in f:
|
||||
# skip comments
|
||||
line_cstr = line
|
||||
hash_ptr = strchr(line_cstr, 35) # ASCII value of '#' is 35
|
||||
if hash_ptr != NULL:
|
||||
line = line[:hash_ptr - line_cstr]
|
||||
|
||||
line_parts = line.split()
|
||||
if len(line_parts) == 0:
|
||||
continue
|
||||
|
||||
target, features = line_parts[0], line_parts[1:]
|
||||
if multilabel:
|
||||
if COLON in target:
|
||||
target, features = [], line_parts[0:]
|
||||
else:
|
||||
target = [float(y) for y in target.split(COMMA)]
|
||||
target.sort()
|
||||
labels.append(tuple(target))
|
||||
else:
|
||||
array.resize_smart(labels, len(labels) + 1)
|
||||
labels[len(labels) - 1] = float(target)
|
||||
|
||||
prev_idx = -1
|
||||
n_features = len(features)
|
||||
if n_features and features[0].startswith(qid_prefix):
|
||||
_, value = features[0].split(COLON, 1)
|
||||
if query_id:
|
||||
query.resize(len(query) + 1)
|
||||
query[len(query) - 1] = np.int64(value)
|
||||
features.pop(0)
|
||||
n_features -= 1
|
||||
|
||||
for i in range(0, n_features):
|
||||
idx_s, value = features[i].split(COLON, 1)
|
||||
idx = int(idx_s)
|
||||
if idx < 0 or not zero_based and idx == 0:
|
||||
raise ValueError(
|
||||
"Invalid index %d in SVMlight/LibSVM data file." % idx)
|
||||
if idx <= prev_idx:
|
||||
raise ValueError("Feature indices in SVMlight/LibSVM data "
|
||||
"file should be sorted and unique.")
|
||||
|
||||
array.resize_smart(indices, len(indices) + 1)
|
||||
indices[len(indices) - 1] = idx
|
||||
|
||||
array.resize_smart(data, len(data) + 1)
|
||||
data[len(data) - 1] = float(value)
|
||||
|
||||
prev_idx = idx
|
||||
|
||||
# increment index pointer array size
|
||||
array.resize_smart(indptr, len(indptr) + 1)
|
||||
indptr[len(indptr) - 1] = len(data)
|
||||
|
||||
if offset_max != -1 and f.tell() > offset_max:
|
||||
# Stop here and let another call deal with the following.
|
||||
break
|
||||
|
||||
return (dtype, data, indices, indptr, labels, query)
|
||||
|
||||
|
||||
# Two fused types are defined to be able to
|
||||
# use all possible combinations of parameters.
|
||||
ctypedef fused int_or_float:
|
||||
cython.integral
|
||||
cython.floating
|
||||
signed long long
|
||||
|
||||
ctypedef fused double_or_longlong:
|
||||
double
|
||||
signed long long
|
||||
|
||||
ctypedef fused int_or_longlong:
|
||||
cython.integral
|
||||
signed long long
|
||||
|
||||
|
||||
def get_dense_row_string(
|
||||
const int_or_float[:, :] X,
|
||||
Py_ssize_t[:] x_inds,
|
||||
double_or_longlong[:] x_vals,
|
||||
Py_ssize_t row,
|
||||
str value_pattern,
|
||||
bint one_based,
|
||||
):
|
||||
cdef:
|
||||
Py_ssize_t row_length = X.shape[1]
|
||||
Py_ssize_t x_nz_used = 0
|
||||
Py_ssize_t k
|
||||
int_or_float val
|
||||
|
||||
for k in range(row_length):
|
||||
val = X[row, k]
|
||||
if val == 0:
|
||||
continue
|
||||
x_inds[x_nz_used] = k
|
||||
x_vals[x_nz_used] = <double_or_longlong> val
|
||||
x_nz_used += 1
|
||||
|
||||
reprs = [
|
||||
value_pattern % (x_inds[i] + one_based, x_vals[i])
|
||||
for i in range(x_nz_used)
|
||||
]
|
||||
|
||||
return " ".join(reprs)
|
||||
|
||||
|
||||
def get_sparse_row_string(
|
||||
int_or_float[:] X_data,
|
||||
int[:] X_indptr,
|
||||
int[:] X_indices,
|
||||
Py_ssize_t row,
|
||||
str value_pattern,
|
||||
bint one_based,
|
||||
):
|
||||
cdef:
|
||||
Py_ssize_t row_start = X_indptr[row]
|
||||
Py_ssize_t row_end = X_indptr[row+1]
|
||||
|
||||
reprs = [
|
||||
value_pattern % (X_indices[i] + one_based, X_data[i])
|
||||
for i in range(row_start, row_end)
|
||||
]
|
||||
|
||||
return " ".join(reprs)
|
||||
|
||||
|
||||
def _dump_svmlight_file(
|
||||
X,
|
||||
y,
|
||||
f,
|
||||
bint multilabel,
|
||||
bint one_based,
|
||||
int_or_longlong[:] query_id,
|
||||
bint X_is_sp,
|
||||
bint y_is_sp,
|
||||
):
|
||||
cdef bint X_is_integral
|
||||
cdef bint query_id_is_not_empty = query_id.size > 0
|
||||
X_is_integral = X.dtype.kind == "i"
|
||||
if X_is_integral:
|
||||
value_pattern = "%d:%d"
|
||||
else:
|
||||
value_pattern = "%d:%.16g"
|
||||
if y.dtype.kind == "i":
|
||||
label_pattern = "%d"
|
||||
else:
|
||||
label_pattern = "%.16g"
|
||||
|
||||
line_pattern = "%s"
|
||||
if query_id_is_not_empty:
|
||||
line_pattern += " qid:%d"
|
||||
line_pattern += " %s\n"
|
||||
|
||||
cdef:
|
||||
Py_ssize_t num_labels = y.shape[1]
|
||||
Py_ssize_t x_len = X.shape[0]
|
||||
Py_ssize_t row_length = X.shape[1]
|
||||
Py_ssize_t i
|
||||
Py_ssize_t j
|
||||
Py_ssize_t col_start
|
||||
Py_ssize_t col_end
|
||||
Py_ssize_t[:] x_inds = np.empty(row_length, dtype=np.intp)
|
||||
signed long long[:] x_vals_int
|
||||
double[:] x_vals_float
|
||||
|
||||
if not X_is_sp:
|
||||
if X_is_integral:
|
||||
x_vals_int = np.zeros(row_length, dtype=np.longlong)
|
||||
else:
|
||||
x_vals_float = np.zeros(row_length, dtype=np.float64)
|
||||
|
||||
for i in range(x_len):
|
||||
if not X_is_sp:
|
||||
if X_is_integral:
|
||||
s = get_dense_row_string(X, x_inds, x_vals_int, i, value_pattern, one_based)
|
||||
else:
|
||||
s = get_dense_row_string(X, x_inds, x_vals_float, i, value_pattern, one_based)
|
||||
else:
|
||||
s = get_sparse_row_string(X.data, X.indptr, X.indices, i, value_pattern, one_based)
|
||||
if multilabel:
|
||||
if y_is_sp:
|
||||
col_start = y.indptr[i]
|
||||
col_end = y.indptr[i+1]
|
||||
labels_str = ','.join(tuple(label_pattern % y.indices[j] for j in range(col_start, col_end) if y.data[j] != 0))
|
||||
else:
|
||||
labels_str = ','.join(label_pattern % j for j in range(num_labels) if y[i, j] != 0)
|
||||
else:
|
||||
if y_is_sp:
|
||||
labels_str = label_pattern % y.data[i]
|
||||
else:
|
||||
labels_str = label_pattern % y[i, 0]
|
||||
|
||||
if query_id_is_not_empty:
|
||||
feat = (labels_str, query_id[i], s)
|
||||
else:
|
||||
feat = (labels_str, s)
|
||||
|
||||
f.write((line_pattern % feat).encode("utf-8"))
|
||||
|
||||
+570
-570
File diff suppressed because it is too large
Load Diff
@@ -1,151 +1,151 @@
|
||||
150,4,setosa,versicolor,virginica
|
||||
5.1,3.5,1.4,0.2,0
|
||||
4.9,3.0,1.4,0.2,0
|
||||
4.7,3.2,1.3,0.2,0
|
||||
4.6,3.1,1.5,0.2,0
|
||||
5.0,3.6,1.4,0.2,0
|
||||
5.4,3.9,1.7,0.4,0
|
||||
4.6,3.4,1.4,0.3,0
|
||||
5.0,3.4,1.5,0.2,0
|
||||
4.4,2.9,1.4,0.2,0
|
||||
4.9,3.1,1.5,0.1,0
|
||||
5.4,3.7,1.5,0.2,0
|
||||
4.8,3.4,1.6,0.2,0
|
||||
4.8,3.0,1.4,0.1,0
|
||||
4.3,3.0,1.1,0.1,0
|
||||
5.8,4.0,1.2,0.2,0
|
||||
5.7,4.4,1.5,0.4,0
|
||||
5.4,3.9,1.3,0.4,0
|
||||
5.1,3.5,1.4,0.3,0
|
||||
5.7,3.8,1.7,0.3,0
|
||||
5.1,3.8,1.5,0.3,0
|
||||
5.4,3.4,1.7,0.2,0
|
||||
5.1,3.7,1.5,0.4,0
|
||||
4.6,3.6,1.0,0.2,0
|
||||
5.1,3.3,1.7,0.5,0
|
||||
4.8,3.4,1.9,0.2,0
|
||||
5.0,3.0,1.6,0.2,0
|
||||
5.0,3.4,1.6,0.4,0
|
||||
5.2,3.5,1.5,0.2,0
|
||||
5.2,3.4,1.4,0.2,0
|
||||
4.7,3.2,1.6,0.2,0
|
||||
4.8,3.1,1.6,0.2,0
|
||||
5.4,3.4,1.5,0.4,0
|
||||
5.2,4.1,1.5,0.1,0
|
||||
5.5,4.2,1.4,0.2,0
|
||||
4.9,3.1,1.5,0.2,0
|
||||
5.0,3.2,1.2,0.2,0
|
||||
5.5,3.5,1.3,0.2,0
|
||||
4.9,3.6,1.4,0.1,0
|
||||
4.4,3.0,1.3,0.2,0
|
||||
5.1,3.4,1.5,0.2,0
|
||||
5.0,3.5,1.3,0.3,0
|
||||
4.5,2.3,1.3,0.3,0
|
||||
4.4,3.2,1.3,0.2,0
|
||||
5.0,3.5,1.6,0.6,0
|
||||
5.1,3.8,1.9,0.4,0
|
||||
4.8,3.0,1.4,0.3,0
|
||||
5.1,3.8,1.6,0.2,0
|
||||
4.6,3.2,1.4,0.2,0
|
||||
5.3,3.7,1.5,0.2,0
|
||||
5.0,3.3,1.4,0.2,0
|
||||
7.0,3.2,4.7,1.4,1
|
||||
6.4,3.2,4.5,1.5,1
|
||||
6.9,3.1,4.9,1.5,1
|
||||
5.5,2.3,4.0,1.3,1
|
||||
6.5,2.8,4.6,1.5,1
|
||||
5.7,2.8,4.5,1.3,1
|
||||
6.3,3.3,4.7,1.6,1
|
||||
4.9,2.4,3.3,1.0,1
|
||||
6.6,2.9,4.6,1.3,1
|
||||
5.2,2.7,3.9,1.4,1
|
||||
5.0,2.0,3.5,1.0,1
|
||||
5.9,3.0,4.2,1.5,1
|
||||
6.0,2.2,4.0,1.0,1
|
||||
6.1,2.9,4.7,1.4,1
|
||||
5.6,2.9,3.6,1.3,1
|
||||
6.7,3.1,4.4,1.4,1
|
||||
5.6,3.0,4.5,1.5,1
|
||||
5.8,2.7,4.1,1.0,1
|
||||
6.2,2.2,4.5,1.5,1
|
||||
5.6,2.5,3.9,1.1,1
|
||||
5.9,3.2,4.8,1.8,1
|
||||
6.1,2.8,4.0,1.3,1
|
||||
6.3,2.5,4.9,1.5,1
|
||||
6.1,2.8,4.7,1.2,1
|
||||
6.4,2.9,4.3,1.3,1
|
||||
6.6,3.0,4.4,1.4,1
|
||||
6.8,2.8,4.8,1.4,1
|
||||
6.7,3.0,5.0,1.7,1
|
||||
6.0,2.9,4.5,1.5,1
|
||||
5.7,2.6,3.5,1.0,1
|
||||
5.5,2.4,3.8,1.1,1
|
||||
5.5,2.4,3.7,1.0,1
|
||||
5.8,2.7,3.9,1.2,1
|
||||
6.0,2.7,5.1,1.6,1
|
||||
5.4,3.0,4.5,1.5,1
|
||||
6.0,3.4,4.5,1.6,1
|
||||
6.7,3.1,4.7,1.5,1
|
||||
6.3,2.3,4.4,1.3,1
|
||||
5.6,3.0,4.1,1.3,1
|
||||
5.5,2.5,4.0,1.3,1
|
||||
5.5,2.6,4.4,1.2,1
|
||||
6.1,3.0,4.6,1.4,1
|
||||
5.8,2.6,4.0,1.2,1
|
||||
5.0,2.3,3.3,1.0,1
|
||||
5.6,2.7,4.2,1.3,1
|
||||
5.7,3.0,4.2,1.2,1
|
||||
5.7,2.9,4.2,1.3,1
|
||||
6.2,2.9,4.3,1.3,1
|
||||
5.1,2.5,3.0,1.1,1
|
||||
5.7,2.8,4.1,1.3,1
|
||||
6.3,3.3,6.0,2.5,2
|
||||
5.8,2.7,5.1,1.9,2
|
||||
7.1,3.0,5.9,2.1,2
|
||||
6.3,2.9,5.6,1.8,2
|
||||
6.5,3.0,5.8,2.2,2
|
||||
7.6,3.0,6.6,2.1,2
|
||||
4.9,2.5,4.5,1.7,2
|
||||
7.3,2.9,6.3,1.8,2
|
||||
6.7,2.5,5.8,1.8,2
|
||||
7.2,3.6,6.1,2.5,2
|
||||
6.5,3.2,5.1,2.0,2
|
||||
6.4,2.7,5.3,1.9,2
|
||||
6.8,3.0,5.5,2.1,2
|
||||
5.7,2.5,5.0,2.0,2
|
||||
5.8,2.8,5.1,2.4,2
|
||||
6.4,3.2,5.3,2.3,2
|
||||
6.5,3.0,5.5,1.8,2
|
||||
7.7,3.8,6.7,2.2,2
|
||||
7.7,2.6,6.9,2.3,2
|
||||
6.0,2.2,5.0,1.5,2
|
||||
6.9,3.2,5.7,2.3,2
|
||||
5.6,2.8,4.9,2.0,2
|
||||
7.7,2.8,6.7,2.0,2
|
||||
6.3,2.7,4.9,1.8,2
|
||||
6.7,3.3,5.7,2.1,2
|
||||
7.2,3.2,6.0,1.8,2
|
||||
6.2,2.8,4.8,1.8,2
|
||||
6.1,3.0,4.9,1.8,2
|
||||
6.4,2.8,5.6,2.1,2
|
||||
7.2,3.0,5.8,1.6,2
|
||||
7.4,2.8,6.1,1.9,2
|
||||
7.9,3.8,6.4,2.0,2
|
||||
6.4,2.8,5.6,2.2,2
|
||||
6.3,2.8,5.1,1.5,2
|
||||
6.1,2.6,5.6,1.4,2
|
||||
7.7,3.0,6.1,2.3,2
|
||||
6.3,3.4,5.6,2.4,2
|
||||
6.4,3.1,5.5,1.8,2
|
||||
6.0,3.0,4.8,1.8,2
|
||||
6.9,3.1,5.4,2.1,2
|
||||
6.7,3.1,5.6,2.4,2
|
||||
6.9,3.1,5.1,2.3,2
|
||||
5.8,2.7,5.1,1.9,2
|
||||
6.8,3.2,5.9,2.3,2
|
||||
6.7,3.3,5.7,2.5,2
|
||||
6.7,3.0,5.2,2.3,2
|
||||
6.3,2.5,5.0,1.9,2
|
||||
6.5,3.0,5.2,2.0,2
|
||||
6.2,3.4,5.4,2.3,2
|
||||
5.9,3.0,5.1,1.8,2
|
||||
150,4,setosa,versicolor,virginica
|
||||
5.1,3.5,1.4,0.2,0
|
||||
4.9,3.0,1.4,0.2,0
|
||||
4.7,3.2,1.3,0.2,0
|
||||
4.6,3.1,1.5,0.2,0
|
||||
5.0,3.6,1.4,0.2,0
|
||||
5.4,3.9,1.7,0.4,0
|
||||
4.6,3.4,1.4,0.3,0
|
||||
5.0,3.4,1.5,0.2,0
|
||||
4.4,2.9,1.4,0.2,0
|
||||
4.9,3.1,1.5,0.1,0
|
||||
5.4,3.7,1.5,0.2,0
|
||||
4.8,3.4,1.6,0.2,0
|
||||
4.8,3.0,1.4,0.1,0
|
||||
4.3,3.0,1.1,0.1,0
|
||||
5.8,4.0,1.2,0.2,0
|
||||
5.7,4.4,1.5,0.4,0
|
||||
5.4,3.9,1.3,0.4,0
|
||||
5.1,3.5,1.4,0.3,0
|
||||
5.7,3.8,1.7,0.3,0
|
||||
5.1,3.8,1.5,0.3,0
|
||||
5.4,3.4,1.7,0.2,0
|
||||
5.1,3.7,1.5,0.4,0
|
||||
4.6,3.6,1.0,0.2,0
|
||||
5.1,3.3,1.7,0.5,0
|
||||
4.8,3.4,1.9,0.2,0
|
||||
5.0,3.0,1.6,0.2,0
|
||||
5.0,3.4,1.6,0.4,0
|
||||
5.2,3.5,1.5,0.2,0
|
||||
5.2,3.4,1.4,0.2,0
|
||||
4.7,3.2,1.6,0.2,0
|
||||
4.8,3.1,1.6,0.2,0
|
||||
5.4,3.4,1.5,0.4,0
|
||||
5.2,4.1,1.5,0.1,0
|
||||
5.5,4.2,1.4,0.2,0
|
||||
4.9,3.1,1.5,0.2,0
|
||||
5.0,3.2,1.2,0.2,0
|
||||
5.5,3.5,1.3,0.2,0
|
||||
4.9,3.6,1.4,0.1,0
|
||||
4.4,3.0,1.3,0.2,0
|
||||
5.1,3.4,1.5,0.2,0
|
||||
5.0,3.5,1.3,0.3,0
|
||||
4.5,2.3,1.3,0.3,0
|
||||
4.4,3.2,1.3,0.2,0
|
||||
5.0,3.5,1.6,0.6,0
|
||||
5.1,3.8,1.9,0.4,0
|
||||
4.8,3.0,1.4,0.3,0
|
||||
5.1,3.8,1.6,0.2,0
|
||||
4.6,3.2,1.4,0.2,0
|
||||
5.3,3.7,1.5,0.2,0
|
||||
5.0,3.3,1.4,0.2,0
|
||||
7.0,3.2,4.7,1.4,1
|
||||
6.4,3.2,4.5,1.5,1
|
||||
6.9,3.1,4.9,1.5,1
|
||||
5.5,2.3,4.0,1.3,1
|
||||
6.5,2.8,4.6,1.5,1
|
||||
5.7,2.8,4.5,1.3,1
|
||||
6.3,3.3,4.7,1.6,1
|
||||
4.9,2.4,3.3,1.0,1
|
||||
6.6,2.9,4.6,1.3,1
|
||||
5.2,2.7,3.9,1.4,1
|
||||
5.0,2.0,3.5,1.0,1
|
||||
5.9,3.0,4.2,1.5,1
|
||||
6.0,2.2,4.0,1.0,1
|
||||
6.1,2.9,4.7,1.4,1
|
||||
5.6,2.9,3.6,1.3,1
|
||||
6.7,3.1,4.4,1.4,1
|
||||
5.6,3.0,4.5,1.5,1
|
||||
5.8,2.7,4.1,1.0,1
|
||||
6.2,2.2,4.5,1.5,1
|
||||
5.6,2.5,3.9,1.1,1
|
||||
5.9,3.2,4.8,1.8,1
|
||||
6.1,2.8,4.0,1.3,1
|
||||
6.3,2.5,4.9,1.5,1
|
||||
6.1,2.8,4.7,1.2,1
|
||||
6.4,2.9,4.3,1.3,1
|
||||
6.6,3.0,4.4,1.4,1
|
||||
6.8,2.8,4.8,1.4,1
|
||||
6.7,3.0,5.0,1.7,1
|
||||
6.0,2.9,4.5,1.5,1
|
||||
5.7,2.6,3.5,1.0,1
|
||||
5.5,2.4,3.8,1.1,1
|
||||
5.5,2.4,3.7,1.0,1
|
||||
5.8,2.7,3.9,1.2,1
|
||||
6.0,2.7,5.1,1.6,1
|
||||
5.4,3.0,4.5,1.5,1
|
||||
6.0,3.4,4.5,1.6,1
|
||||
6.7,3.1,4.7,1.5,1
|
||||
6.3,2.3,4.4,1.3,1
|
||||
5.6,3.0,4.1,1.3,1
|
||||
5.5,2.5,4.0,1.3,1
|
||||
5.5,2.6,4.4,1.2,1
|
||||
6.1,3.0,4.6,1.4,1
|
||||
5.8,2.6,4.0,1.2,1
|
||||
5.0,2.3,3.3,1.0,1
|
||||
5.6,2.7,4.2,1.3,1
|
||||
5.7,3.0,4.2,1.2,1
|
||||
5.7,2.9,4.2,1.3,1
|
||||
6.2,2.9,4.3,1.3,1
|
||||
5.1,2.5,3.0,1.1,1
|
||||
5.7,2.8,4.1,1.3,1
|
||||
6.3,3.3,6.0,2.5,2
|
||||
5.8,2.7,5.1,1.9,2
|
||||
7.1,3.0,5.9,2.1,2
|
||||
6.3,2.9,5.6,1.8,2
|
||||
6.5,3.0,5.8,2.2,2
|
||||
7.6,3.0,6.6,2.1,2
|
||||
4.9,2.5,4.5,1.7,2
|
||||
7.3,2.9,6.3,1.8,2
|
||||
6.7,2.5,5.8,1.8,2
|
||||
7.2,3.6,6.1,2.5,2
|
||||
6.5,3.2,5.1,2.0,2
|
||||
6.4,2.7,5.3,1.9,2
|
||||
6.8,3.0,5.5,2.1,2
|
||||
5.7,2.5,5.0,2.0,2
|
||||
5.8,2.8,5.1,2.4,2
|
||||
6.4,3.2,5.3,2.3,2
|
||||
6.5,3.0,5.5,1.8,2
|
||||
7.7,3.8,6.7,2.2,2
|
||||
7.7,2.6,6.9,2.3,2
|
||||
6.0,2.2,5.0,1.5,2
|
||||
6.9,3.2,5.7,2.3,2
|
||||
5.6,2.8,4.9,2.0,2
|
||||
7.7,2.8,6.7,2.0,2
|
||||
6.3,2.7,4.9,1.8,2
|
||||
6.7,3.3,5.7,2.1,2
|
||||
7.2,3.2,6.0,1.8,2
|
||||
6.2,2.8,4.8,1.8,2
|
||||
6.1,3.0,4.9,1.8,2
|
||||
6.4,2.8,5.6,2.1,2
|
||||
7.2,3.0,5.8,1.6,2
|
||||
7.4,2.8,6.1,1.9,2
|
||||
7.9,3.8,6.4,2.0,2
|
||||
6.4,2.8,5.6,2.2,2
|
||||
6.3,2.8,5.1,1.5,2
|
||||
6.1,2.6,5.6,1.4,2
|
||||
7.7,3.0,6.1,2.3,2
|
||||
6.3,3.4,5.6,2.4,2
|
||||
6.4,3.1,5.5,1.8,2
|
||||
6.0,3.0,4.8,1.8,2
|
||||
6.9,3.1,5.4,2.1,2
|
||||
6.7,3.1,5.6,2.4,2
|
||||
6.9,3.1,5.1,2.3,2
|
||||
5.8,2.7,5.1,1.9,2
|
||||
6.8,3.2,5.9,2.3,2
|
||||
6.7,3.3,5.7,2.5,2
|
||||
6.7,3.0,5.2,2.3,2
|
||||
6.3,2.5,5.0,1.9,2
|
||||
6.5,3.0,5.2,2.0,2
|
||||
6.2,3.4,5.4,2.3,2
|
||||
5.9,3.0,5.1,1.8,2
|
||||
|
||||
|
+21
-21
@@ -1,21 +1,21 @@
|
||||
Chins Situps Jumps
|
||||
5 162 60
|
||||
2 110 60
|
||||
12 101 101
|
||||
12 105 37
|
||||
13 155 58
|
||||
4 101 42
|
||||
8 101 38
|
||||
6 125 40
|
||||
15 200 40
|
||||
17 251 250
|
||||
17 120 38
|
||||
13 210 115
|
||||
14 215 105
|
||||
1 50 50
|
||||
6 70 31
|
||||
12 210 120
|
||||
4 60 25
|
||||
11 230 80
|
||||
15 225 73
|
||||
2 110 43
|
||||
Chins Situps Jumps
|
||||
5 162 60
|
||||
2 110 60
|
||||
12 101 101
|
||||
12 105 37
|
||||
13 155 58
|
||||
4 101 42
|
||||
8 101 38
|
||||
6 125 40
|
||||
15 200 40
|
||||
17 251 250
|
||||
17 120 38
|
||||
13 210 115
|
||||
14 215 105
|
||||
1 50 50
|
||||
6 70 31
|
||||
12 210 120
|
||||
4 60 25
|
||||
11 230 80
|
||||
15 225 73
|
||||
2 110 43
|
||||
|
||||
|
+21
-21
@@ -1,21 +1,21 @@
|
||||
Weight Waist Pulse
|
||||
191 36 50
|
||||
189 37 52
|
||||
193 38 58
|
||||
162 35 62
|
||||
189 35 46
|
||||
182 36 56
|
||||
211 38 56
|
||||
167 34 60
|
||||
176 31 74
|
||||
154 33 56
|
||||
169 34 50
|
||||
166 33 52
|
||||
154 34 64
|
||||
247 46 50
|
||||
193 36 46
|
||||
202 37 62
|
||||
176 37 54
|
||||
157 32 52
|
||||
156 33 54
|
||||
138 33 68
|
||||
Weight Waist Pulse
|
||||
191 36 50
|
||||
189 37 52
|
||||
193 38 58
|
||||
162 35 62
|
||||
189 35 46
|
||||
182 36 56
|
||||
211 38 56
|
||||
167 34 60
|
||||
176 31 74
|
||||
154 33 56
|
||||
169 34 50
|
||||
166 33 52
|
||||
154 34 64
|
||||
247 46 50
|
||||
193 36 46
|
||||
202 37 62
|
||||
176 37 54
|
||||
157 32 52
|
||||
156 33 54
|
||||
138 33 68
|
||||
|
||||
|
@@ -1,179 +1,179 @@
|
||||
178,13,class_0,class_1,class_2
|
||||
14.23,1.71,2.43,15.6,127,2.8,3.06,0.28,2.29,5.64,1.04,3.92,1065,0
|
||||
13.2,1.78,2.14,11.2,100,2.65,2.76,0.26,1.28,4.38,1.05,3.4,1050,0
|
||||
13.16,2.36,2.67,18.6,101,2.8,3.24,0.3,2.81,5.68,1.03,3.17,1185,0
|
||||
14.37,1.95,2.5,16.8,113,3.85,3.49,0.24,2.18,7.8,0.86,3.45,1480,0
|
||||
13.24,2.59,2.87,21,118,2.8,2.69,0.39,1.82,4.32,1.04,2.93,735,0
|
||||
14.2,1.76,2.45,15.2,112,3.27,3.39,0.34,1.97,6.75,1.05,2.85,1450,0
|
||||
14.39,1.87,2.45,14.6,96,2.5,2.52,0.3,1.98,5.25,1.02,3.58,1290,0
|
||||
14.06,2.15,2.61,17.6,121,2.6,2.51,0.31,1.25,5.05,1.06,3.58,1295,0
|
||||
14.83,1.64,2.17,14,97,2.8,2.98,0.29,1.98,5.2,1.08,2.85,1045,0
|
||||
13.86,1.35,2.27,16,98,2.98,3.15,0.22,1.85,7.22,1.01,3.55,1045,0
|
||||
14.1,2.16,2.3,18,105,2.95,3.32,0.22,2.38,5.75,1.25,3.17,1510,0
|
||||
14.12,1.48,2.32,16.8,95,2.2,2.43,0.26,1.57,5,1.17,2.82,1280,0
|
||||
13.75,1.73,2.41,16,89,2.6,2.76,0.29,1.81,5.6,1.15,2.9,1320,0
|
||||
14.75,1.73,2.39,11.4,91,3.1,3.69,0.43,2.81,5.4,1.25,2.73,1150,0
|
||||
14.38,1.87,2.38,12,102,3.3,3.64,0.29,2.96,7.5,1.2,3,1547,0
|
||||
13.63,1.81,2.7,17.2,112,2.85,2.91,0.3,1.46,7.3,1.28,2.88,1310,0
|
||||
14.3,1.92,2.72,20,120,2.8,3.14,0.33,1.97,6.2,1.07,2.65,1280,0
|
||||
13.83,1.57,2.62,20,115,2.95,3.4,0.4,1.72,6.6,1.13,2.57,1130,0
|
||||
14.19,1.59,2.48,16.5,108,3.3,3.93,0.32,1.86,8.7,1.23,2.82,1680,0
|
||||
13.64,3.1,2.56,15.2,116,2.7,3.03,0.17,1.66,5.1,0.96,3.36,845,0
|
||||
14.06,1.63,2.28,16,126,3,3.17,0.24,2.1,5.65,1.09,3.71,780,0
|
||||
12.93,3.8,2.65,18.6,102,2.41,2.41,0.25,1.98,4.5,1.03,3.52,770,0
|
||||
13.71,1.86,2.36,16.6,101,2.61,2.88,0.27,1.69,3.8,1.11,4,1035,0
|
||||
12.85,1.6,2.52,17.8,95,2.48,2.37,0.26,1.46,3.93,1.09,3.63,1015,0
|
||||
13.5,1.81,2.61,20,96,2.53,2.61,0.28,1.66,3.52,1.12,3.82,845,0
|
||||
13.05,2.05,3.22,25,124,2.63,2.68,0.47,1.92,3.58,1.13,3.2,830,0
|
||||
13.39,1.77,2.62,16.1,93,2.85,2.94,0.34,1.45,4.8,0.92,3.22,1195,0
|
||||
13.3,1.72,2.14,17,94,2.4,2.19,0.27,1.35,3.95,1.02,2.77,1285,0
|
||||
13.87,1.9,2.8,19.4,107,2.95,2.97,0.37,1.76,4.5,1.25,3.4,915,0
|
||||
14.02,1.68,2.21,16,96,2.65,2.33,0.26,1.98,4.7,1.04,3.59,1035,0
|
||||
13.73,1.5,2.7,22.5,101,3,3.25,0.29,2.38,5.7,1.19,2.71,1285,0
|
||||
13.58,1.66,2.36,19.1,106,2.86,3.19,0.22,1.95,6.9,1.09,2.88,1515,0
|
||||
13.68,1.83,2.36,17.2,104,2.42,2.69,0.42,1.97,3.84,1.23,2.87,990,0
|
||||
13.76,1.53,2.7,19.5,132,2.95,2.74,0.5,1.35,5.4,1.25,3,1235,0
|
||||
13.51,1.8,2.65,19,110,2.35,2.53,0.29,1.54,4.2,1.1,2.87,1095,0
|
||||
13.48,1.81,2.41,20.5,100,2.7,2.98,0.26,1.86,5.1,1.04,3.47,920,0
|
||||
13.28,1.64,2.84,15.5,110,2.6,2.68,0.34,1.36,4.6,1.09,2.78,880,0
|
||||
13.05,1.65,2.55,18,98,2.45,2.43,0.29,1.44,4.25,1.12,2.51,1105,0
|
||||
13.07,1.5,2.1,15.5,98,2.4,2.64,0.28,1.37,3.7,1.18,2.69,1020,0
|
||||
14.22,3.99,2.51,13.2,128,3,3.04,0.2,2.08,5.1,0.89,3.53,760,0
|
||||
13.56,1.71,2.31,16.2,117,3.15,3.29,0.34,2.34,6.13,0.95,3.38,795,0
|
||||
13.41,3.84,2.12,18.8,90,2.45,2.68,0.27,1.48,4.28,0.91,3,1035,0
|
||||
13.88,1.89,2.59,15,101,3.25,3.56,0.17,1.7,5.43,0.88,3.56,1095,0
|
||||
13.24,3.98,2.29,17.5,103,2.64,2.63,0.32,1.66,4.36,0.82,3,680,0
|
||||
13.05,1.77,2.1,17,107,3,3,0.28,2.03,5.04,0.88,3.35,885,0
|
||||
14.21,4.04,2.44,18.9,111,2.85,2.65,0.3,1.25,5.24,0.87,3.33,1080,0
|
||||
14.38,3.59,2.28,16,102,3.25,3.17,0.27,2.19,4.9,1.04,3.44,1065,0
|
||||
13.9,1.68,2.12,16,101,3.1,3.39,0.21,2.14,6.1,0.91,3.33,985,0
|
||||
14.1,2.02,2.4,18.8,103,2.75,2.92,0.32,2.38,6.2,1.07,2.75,1060,0
|
||||
13.94,1.73,2.27,17.4,108,2.88,3.54,0.32,2.08,8.9,1.12,3.1,1260,0
|
||||
13.05,1.73,2.04,12.4,92,2.72,3.27,0.17,2.91,7.2,1.12,2.91,1150,0
|
||||
13.83,1.65,2.6,17.2,94,2.45,2.99,0.22,2.29,5.6,1.24,3.37,1265,0
|
||||
13.82,1.75,2.42,14,111,3.88,3.74,0.32,1.87,7.05,1.01,3.26,1190,0
|
||||
13.77,1.9,2.68,17.1,115,3,2.79,0.39,1.68,6.3,1.13,2.93,1375,0
|
||||
13.74,1.67,2.25,16.4,118,2.6,2.9,0.21,1.62,5.85,0.92,3.2,1060,0
|
||||
13.56,1.73,2.46,20.5,116,2.96,2.78,0.2,2.45,6.25,0.98,3.03,1120,0
|
||||
14.22,1.7,2.3,16.3,118,3.2,3,0.26,2.03,6.38,0.94,3.31,970,0
|
||||
13.29,1.97,2.68,16.8,102,3,3.23,0.31,1.66,6,1.07,2.84,1270,0
|
||||
13.72,1.43,2.5,16.7,108,3.4,3.67,0.19,2.04,6.8,0.89,2.87,1285,0
|
||||
12.37,0.94,1.36,10.6,88,1.98,0.57,0.28,0.42,1.95,1.05,1.82,520,1
|
||||
12.33,1.1,2.28,16,101,2.05,1.09,0.63,0.41,3.27,1.25,1.67,680,1
|
||||
12.64,1.36,2.02,16.8,100,2.02,1.41,0.53,0.62,5.75,0.98,1.59,450,1
|
||||
13.67,1.25,1.92,18,94,2.1,1.79,0.32,0.73,3.8,1.23,2.46,630,1
|
||||
12.37,1.13,2.16,19,87,3.5,3.1,0.19,1.87,4.45,1.22,2.87,420,1
|
||||
12.17,1.45,2.53,19,104,1.89,1.75,0.45,1.03,2.95,1.45,2.23,355,1
|
||||
12.37,1.21,2.56,18.1,98,2.42,2.65,0.37,2.08,4.6,1.19,2.3,678,1
|
||||
13.11,1.01,1.7,15,78,2.98,3.18,0.26,2.28,5.3,1.12,3.18,502,1
|
||||
12.37,1.17,1.92,19.6,78,2.11,2,0.27,1.04,4.68,1.12,3.48,510,1
|
||||
13.34,0.94,2.36,17,110,2.53,1.3,0.55,0.42,3.17,1.02,1.93,750,1
|
||||
12.21,1.19,1.75,16.8,151,1.85,1.28,0.14,2.5,2.85,1.28,3.07,718,1
|
||||
12.29,1.61,2.21,20.4,103,1.1,1.02,0.37,1.46,3.05,0.906,1.82,870,1
|
||||
13.86,1.51,2.67,25,86,2.95,2.86,0.21,1.87,3.38,1.36,3.16,410,1
|
||||
13.49,1.66,2.24,24,87,1.88,1.84,0.27,1.03,3.74,0.98,2.78,472,1
|
||||
12.99,1.67,2.6,30,139,3.3,2.89,0.21,1.96,3.35,1.31,3.5,985,1
|
||||
11.96,1.09,2.3,21,101,3.38,2.14,0.13,1.65,3.21,0.99,3.13,886,1
|
||||
11.66,1.88,1.92,16,97,1.61,1.57,0.34,1.15,3.8,1.23,2.14,428,1
|
||||
13.03,0.9,1.71,16,86,1.95,2.03,0.24,1.46,4.6,1.19,2.48,392,1
|
||||
11.84,2.89,2.23,18,112,1.72,1.32,0.43,0.95,2.65,0.96,2.52,500,1
|
||||
12.33,0.99,1.95,14.8,136,1.9,1.85,0.35,2.76,3.4,1.06,2.31,750,1
|
||||
12.7,3.87,2.4,23,101,2.83,2.55,0.43,1.95,2.57,1.19,3.13,463,1
|
||||
12,0.92,2,19,86,2.42,2.26,0.3,1.43,2.5,1.38,3.12,278,1
|
||||
12.72,1.81,2.2,18.8,86,2.2,2.53,0.26,1.77,3.9,1.16,3.14,714,1
|
||||
12.08,1.13,2.51,24,78,2,1.58,0.4,1.4,2.2,1.31,2.72,630,1
|
||||
13.05,3.86,2.32,22.5,85,1.65,1.59,0.61,1.62,4.8,0.84,2.01,515,1
|
||||
11.84,0.89,2.58,18,94,2.2,2.21,0.22,2.35,3.05,0.79,3.08,520,1
|
||||
12.67,0.98,2.24,18,99,2.2,1.94,0.3,1.46,2.62,1.23,3.16,450,1
|
||||
12.16,1.61,2.31,22.8,90,1.78,1.69,0.43,1.56,2.45,1.33,2.26,495,1
|
||||
11.65,1.67,2.62,26,88,1.92,1.61,0.4,1.34,2.6,1.36,3.21,562,1
|
||||
11.64,2.06,2.46,21.6,84,1.95,1.69,0.48,1.35,2.8,1,2.75,680,1
|
||||
12.08,1.33,2.3,23.6,70,2.2,1.59,0.42,1.38,1.74,1.07,3.21,625,1
|
||||
12.08,1.83,2.32,18.5,81,1.6,1.5,0.52,1.64,2.4,1.08,2.27,480,1
|
||||
12,1.51,2.42,22,86,1.45,1.25,0.5,1.63,3.6,1.05,2.65,450,1
|
||||
12.69,1.53,2.26,20.7,80,1.38,1.46,0.58,1.62,3.05,0.96,2.06,495,1
|
||||
12.29,2.83,2.22,18,88,2.45,2.25,0.25,1.99,2.15,1.15,3.3,290,1
|
||||
11.62,1.99,2.28,18,98,3.02,2.26,0.17,1.35,3.25,1.16,2.96,345,1
|
||||
12.47,1.52,2.2,19,162,2.5,2.27,0.32,3.28,2.6,1.16,2.63,937,1
|
||||
11.81,2.12,2.74,21.5,134,1.6,0.99,0.14,1.56,2.5,0.95,2.26,625,1
|
||||
12.29,1.41,1.98,16,85,2.55,2.5,0.29,1.77,2.9,1.23,2.74,428,1
|
||||
12.37,1.07,2.1,18.5,88,3.52,3.75,0.24,1.95,4.5,1.04,2.77,660,1
|
||||
12.29,3.17,2.21,18,88,2.85,2.99,0.45,2.81,2.3,1.42,2.83,406,1
|
||||
12.08,2.08,1.7,17.5,97,2.23,2.17,0.26,1.4,3.3,1.27,2.96,710,1
|
||||
12.6,1.34,1.9,18.5,88,1.45,1.36,0.29,1.35,2.45,1.04,2.77,562,1
|
||||
12.34,2.45,2.46,21,98,2.56,2.11,0.34,1.31,2.8,0.8,3.38,438,1
|
||||
11.82,1.72,1.88,19.5,86,2.5,1.64,0.37,1.42,2.06,0.94,2.44,415,1
|
||||
12.51,1.73,1.98,20.5,85,2.2,1.92,0.32,1.48,2.94,1.04,3.57,672,1
|
||||
12.42,2.55,2.27,22,90,1.68,1.84,0.66,1.42,2.7,0.86,3.3,315,1
|
||||
12.25,1.73,2.12,19,80,1.65,2.03,0.37,1.63,3.4,1,3.17,510,1
|
||||
12.72,1.75,2.28,22.5,84,1.38,1.76,0.48,1.63,3.3,0.88,2.42,488,1
|
||||
12.22,1.29,1.94,19,92,2.36,2.04,0.39,2.08,2.7,0.86,3.02,312,1
|
||||
11.61,1.35,2.7,20,94,2.74,2.92,0.29,2.49,2.65,0.96,3.26,680,1
|
||||
11.46,3.74,1.82,19.5,107,3.18,2.58,0.24,3.58,2.9,0.75,2.81,562,1
|
||||
12.52,2.43,2.17,21,88,2.55,2.27,0.26,1.22,2,0.9,2.78,325,1
|
||||
11.76,2.68,2.92,20,103,1.75,2.03,0.6,1.05,3.8,1.23,2.5,607,1
|
||||
11.41,0.74,2.5,21,88,2.48,2.01,0.42,1.44,3.08,1.1,2.31,434,1
|
||||
12.08,1.39,2.5,22.5,84,2.56,2.29,0.43,1.04,2.9,0.93,3.19,385,1
|
||||
11.03,1.51,2.2,21.5,85,2.46,2.17,0.52,2.01,1.9,1.71,2.87,407,1
|
||||
11.82,1.47,1.99,20.8,86,1.98,1.6,0.3,1.53,1.95,0.95,3.33,495,1
|
||||
12.42,1.61,2.19,22.5,108,2,2.09,0.34,1.61,2.06,1.06,2.96,345,1
|
||||
12.77,3.43,1.98,16,80,1.63,1.25,0.43,0.83,3.4,0.7,2.12,372,1
|
||||
12,3.43,2,19,87,2,1.64,0.37,1.87,1.28,0.93,3.05,564,1
|
||||
11.45,2.4,2.42,20,96,2.9,2.79,0.32,1.83,3.25,0.8,3.39,625,1
|
||||
11.56,2.05,3.23,28.5,119,3.18,5.08,0.47,1.87,6,0.93,3.69,465,1
|
||||
12.42,4.43,2.73,26.5,102,2.2,2.13,0.43,1.71,2.08,0.92,3.12,365,1
|
||||
13.05,5.8,2.13,21.5,86,2.62,2.65,0.3,2.01,2.6,0.73,3.1,380,1
|
||||
11.87,4.31,2.39,21,82,2.86,3.03,0.21,2.91,2.8,0.75,3.64,380,1
|
||||
12.07,2.16,2.17,21,85,2.6,2.65,0.37,1.35,2.76,0.86,3.28,378,1
|
||||
12.43,1.53,2.29,21.5,86,2.74,3.15,0.39,1.77,3.94,0.69,2.84,352,1
|
||||
11.79,2.13,2.78,28.5,92,2.13,2.24,0.58,1.76,3,0.97,2.44,466,1
|
||||
12.37,1.63,2.3,24.5,88,2.22,2.45,0.4,1.9,2.12,0.89,2.78,342,1
|
||||
12.04,4.3,2.38,22,80,2.1,1.75,0.42,1.35,2.6,0.79,2.57,580,1
|
||||
12.86,1.35,2.32,18,122,1.51,1.25,0.21,0.94,4.1,0.76,1.29,630,2
|
||||
12.88,2.99,2.4,20,104,1.3,1.22,0.24,0.83,5.4,0.74,1.42,530,2
|
||||
12.81,2.31,2.4,24,98,1.15,1.09,0.27,0.83,5.7,0.66,1.36,560,2
|
||||
12.7,3.55,2.36,21.5,106,1.7,1.2,0.17,0.84,5,0.78,1.29,600,2
|
||||
12.51,1.24,2.25,17.5,85,2,0.58,0.6,1.25,5.45,0.75,1.51,650,2
|
||||
12.6,2.46,2.2,18.5,94,1.62,0.66,0.63,0.94,7.1,0.73,1.58,695,2
|
||||
12.25,4.72,2.54,21,89,1.38,0.47,0.53,0.8,3.85,0.75,1.27,720,2
|
||||
12.53,5.51,2.64,25,96,1.79,0.6,0.63,1.1,5,0.82,1.69,515,2
|
||||
13.49,3.59,2.19,19.5,88,1.62,0.48,0.58,0.88,5.7,0.81,1.82,580,2
|
||||
12.84,2.96,2.61,24,101,2.32,0.6,0.53,0.81,4.92,0.89,2.15,590,2
|
||||
12.93,2.81,2.7,21,96,1.54,0.5,0.53,0.75,4.6,0.77,2.31,600,2
|
||||
13.36,2.56,2.35,20,89,1.4,0.5,0.37,0.64,5.6,0.7,2.47,780,2
|
||||
13.52,3.17,2.72,23.5,97,1.55,0.52,0.5,0.55,4.35,0.89,2.06,520,2
|
||||
13.62,4.95,2.35,20,92,2,0.8,0.47,1.02,4.4,0.91,2.05,550,2
|
||||
12.25,3.88,2.2,18.5,112,1.38,0.78,0.29,1.14,8.21,0.65,2,855,2
|
||||
13.16,3.57,2.15,21,102,1.5,0.55,0.43,1.3,4,0.6,1.68,830,2
|
||||
13.88,5.04,2.23,20,80,0.98,0.34,0.4,0.68,4.9,0.58,1.33,415,2
|
||||
12.87,4.61,2.48,21.5,86,1.7,0.65,0.47,0.86,7.65,0.54,1.86,625,2
|
||||
13.32,3.24,2.38,21.5,92,1.93,0.76,0.45,1.25,8.42,0.55,1.62,650,2
|
||||
13.08,3.9,2.36,21.5,113,1.41,1.39,0.34,1.14,9.4,0.57,1.33,550,2
|
||||
13.5,3.12,2.62,24,123,1.4,1.57,0.22,1.25,8.6,0.59,1.3,500,2
|
||||
12.79,2.67,2.48,22,112,1.48,1.36,0.24,1.26,10.8,0.48,1.47,480,2
|
||||
13.11,1.9,2.75,25.5,116,2.2,1.28,0.26,1.56,7.1,0.61,1.33,425,2
|
||||
13.23,3.3,2.28,18.5,98,1.8,0.83,0.61,1.87,10.52,0.56,1.51,675,2
|
||||
12.58,1.29,2.1,20,103,1.48,0.58,0.53,1.4,7.6,0.58,1.55,640,2
|
||||
13.17,5.19,2.32,22,93,1.74,0.63,0.61,1.55,7.9,0.6,1.48,725,2
|
||||
13.84,4.12,2.38,19.5,89,1.8,0.83,0.48,1.56,9.01,0.57,1.64,480,2
|
||||
12.45,3.03,2.64,27,97,1.9,0.58,0.63,1.14,7.5,0.67,1.73,880,2
|
||||
14.34,1.68,2.7,25,98,2.8,1.31,0.53,2.7,13,0.57,1.96,660,2
|
||||
13.48,1.67,2.64,22.5,89,2.6,1.1,0.52,2.29,11.75,0.57,1.78,620,2
|
||||
12.36,3.83,2.38,21,88,2.3,0.92,0.5,1.04,7.65,0.56,1.58,520,2
|
||||
13.69,3.26,2.54,20,107,1.83,0.56,0.5,0.8,5.88,0.96,1.82,680,2
|
||||
12.85,3.27,2.58,22,106,1.65,0.6,0.6,0.96,5.58,0.87,2.11,570,2
|
||||
12.96,3.45,2.35,18.5,106,1.39,0.7,0.4,0.94,5.28,0.68,1.75,675,2
|
||||
13.78,2.76,2.3,22,90,1.35,0.68,0.41,1.03,9.58,0.7,1.68,615,2
|
||||
13.73,4.36,2.26,22.5,88,1.28,0.47,0.52,1.15,6.62,0.78,1.75,520,2
|
||||
13.45,3.7,2.6,23,111,1.7,0.92,0.43,1.46,10.68,0.85,1.56,695,2
|
||||
12.82,3.37,2.3,19.5,88,1.48,0.66,0.4,0.97,10.26,0.72,1.75,685,2
|
||||
13.58,2.58,2.69,24.5,105,1.55,0.84,0.39,1.54,8.66,0.74,1.8,750,2
|
||||
13.4,4.6,2.86,25,112,1.98,0.96,0.27,1.11,8.5,0.67,1.92,630,2
|
||||
12.2,3.03,2.32,19,96,1.25,0.49,0.4,0.73,5.5,0.66,1.83,510,2
|
||||
12.77,2.39,2.28,19.5,86,1.39,0.51,0.48,0.64,9.899999,0.57,1.63,470,2
|
||||
14.16,2.51,2.48,20,91,1.68,0.7,0.44,1.24,9.7,0.62,1.71,660,2
|
||||
13.71,5.65,2.45,20.5,95,1.68,0.61,0.52,1.06,7.7,0.64,1.74,740,2
|
||||
13.4,3.91,2.48,23,102,1.8,0.75,0.43,1.41,7.3,0.7,1.56,750,2
|
||||
13.27,4.28,2.26,20,120,1.59,0.69,0.43,1.35,10.2,0.59,1.56,835,2
|
||||
13.17,2.59,2.37,20,120,1.65,0.68,0.53,1.46,9.3,0.6,1.62,840,2
|
||||
14.13,4.1,2.74,24.5,96,2.05,0.76,0.56,1.35,9.2,0.61,1.6,560,2
|
||||
178,13,class_0,class_1,class_2
|
||||
14.23,1.71,2.43,15.6,127,2.8,3.06,0.28,2.29,5.64,1.04,3.92,1065,0
|
||||
13.2,1.78,2.14,11.2,100,2.65,2.76,0.26,1.28,4.38,1.05,3.4,1050,0
|
||||
13.16,2.36,2.67,18.6,101,2.8,3.24,0.3,2.81,5.68,1.03,3.17,1185,0
|
||||
14.37,1.95,2.5,16.8,113,3.85,3.49,0.24,2.18,7.8,0.86,3.45,1480,0
|
||||
13.24,2.59,2.87,21,118,2.8,2.69,0.39,1.82,4.32,1.04,2.93,735,0
|
||||
14.2,1.76,2.45,15.2,112,3.27,3.39,0.34,1.97,6.75,1.05,2.85,1450,0
|
||||
14.39,1.87,2.45,14.6,96,2.5,2.52,0.3,1.98,5.25,1.02,3.58,1290,0
|
||||
14.06,2.15,2.61,17.6,121,2.6,2.51,0.31,1.25,5.05,1.06,3.58,1295,0
|
||||
14.83,1.64,2.17,14,97,2.8,2.98,0.29,1.98,5.2,1.08,2.85,1045,0
|
||||
13.86,1.35,2.27,16,98,2.98,3.15,0.22,1.85,7.22,1.01,3.55,1045,0
|
||||
14.1,2.16,2.3,18,105,2.95,3.32,0.22,2.38,5.75,1.25,3.17,1510,0
|
||||
14.12,1.48,2.32,16.8,95,2.2,2.43,0.26,1.57,5,1.17,2.82,1280,0
|
||||
13.75,1.73,2.41,16,89,2.6,2.76,0.29,1.81,5.6,1.15,2.9,1320,0
|
||||
14.75,1.73,2.39,11.4,91,3.1,3.69,0.43,2.81,5.4,1.25,2.73,1150,0
|
||||
14.38,1.87,2.38,12,102,3.3,3.64,0.29,2.96,7.5,1.2,3,1547,0
|
||||
13.63,1.81,2.7,17.2,112,2.85,2.91,0.3,1.46,7.3,1.28,2.88,1310,0
|
||||
14.3,1.92,2.72,20,120,2.8,3.14,0.33,1.97,6.2,1.07,2.65,1280,0
|
||||
13.83,1.57,2.62,20,115,2.95,3.4,0.4,1.72,6.6,1.13,2.57,1130,0
|
||||
14.19,1.59,2.48,16.5,108,3.3,3.93,0.32,1.86,8.7,1.23,2.82,1680,0
|
||||
13.64,3.1,2.56,15.2,116,2.7,3.03,0.17,1.66,5.1,0.96,3.36,845,0
|
||||
14.06,1.63,2.28,16,126,3,3.17,0.24,2.1,5.65,1.09,3.71,780,0
|
||||
12.93,3.8,2.65,18.6,102,2.41,2.41,0.25,1.98,4.5,1.03,3.52,770,0
|
||||
13.71,1.86,2.36,16.6,101,2.61,2.88,0.27,1.69,3.8,1.11,4,1035,0
|
||||
12.85,1.6,2.52,17.8,95,2.48,2.37,0.26,1.46,3.93,1.09,3.63,1015,0
|
||||
13.5,1.81,2.61,20,96,2.53,2.61,0.28,1.66,3.52,1.12,3.82,845,0
|
||||
13.05,2.05,3.22,25,124,2.63,2.68,0.47,1.92,3.58,1.13,3.2,830,0
|
||||
13.39,1.77,2.62,16.1,93,2.85,2.94,0.34,1.45,4.8,0.92,3.22,1195,0
|
||||
13.3,1.72,2.14,17,94,2.4,2.19,0.27,1.35,3.95,1.02,2.77,1285,0
|
||||
13.87,1.9,2.8,19.4,107,2.95,2.97,0.37,1.76,4.5,1.25,3.4,915,0
|
||||
14.02,1.68,2.21,16,96,2.65,2.33,0.26,1.98,4.7,1.04,3.59,1035,0
|
||||
13.73,1.5,2.7,22.5,101,3,3.25,0.29,2.38,5.7,1.19,2.71,1285,0
|
||||
13.58,1.66,2.36,19.1,106,2.86,3.19,0.22,1.95,6.9,1.09,2.88,1515,0
|
||||
13.68,1.83,2.36,17.2,104,2.42,2.69,0.42,1.97,3.84,1.23,2.87,990,0
|
||||
13.76,1.53,2.7,19.5,132,2.95,2.74,0.5,1.35,5.4,1.25,3,1235,0
|
||||
13.51,1.8,2.65,19,110,2.35,2.53,0.29,1.54,4.2,1.1,2.87,1095,0
|
||||
13.48,1.81,2.41,20.5,100,2.7,2.98,0.26,1.86,5.1,1.04,3.47,920,0
|
||||
13.28,1.64,2.84,15.5,110,2.6,2.68,0.34,1.36,4.6,1.09,2.78,880,0
|
||||
13.05,1.65,2.55,18,98,2.45,2.43,0.29,1.44,4.25,1.12,2.51,1105,0
|
||||
13.07,1.5,2.1,15.5,98,2.4,2.64,0.28,1.37,3.7,1.18,2.69,1020,0
|
||||
14.22,3.99,2.51,13.2,128,3,3.04,0.2,2.08,5.1,0.89,3.53,760,0
|
||||
13.56,1.71,2.31,16.2,117,3.15,3.29,0.34,2.34,6.13,0.95,3.38,795,0
|
||||
13.41,3.84,2.12,18.8,90,2.45,2.68,0.27,1.48,4.28,0.91,3,1035,0
|
||||
13.88,1.89,2.59,15,101,3.25,3.56,0.17,1.7,5.43,0.88,3.56,1095,0
|
||||
13.24,3.98,2.29,17.5,103,2.64,2.63,0.32,1.66,4.36,0.82,3,680,0
|
||||
13.05,1.77,2.1,17,107,3,3,0.28,2.03,5.04,0.88,3.35,885,0
|
||||
14.21,4.04,2.44,18.9,111,2.85,2.65,0.3,1.25,5.24,0.87,3.33,1080,0
|
||||
14.38,3.59,2.28,16,102,3.25,3.17,0.27,2.19,4.9,1.04,3.44,1065,0
|
||||
13.9,1.68,2.12,16,101,3.1,3.39,0.21,2.14,6.1,0.91,3.33,985,0
|
||||
14.1,2.02,2.4,18.8,103,2.75,2.92,0.32,2.38,6.2,1.07,2.75,1060,0
|
||||
13.94,1.73,2.27,17.4,108,2.88,3.54,0.32,2.08,8.9,1.12,3.1,1260,0
|
||||
13.05,1.73,2.04,12.4,92,2.72,3.27,0.17,2.91,7.2,1.12,2.91,1150,0
|
||||
13.83,1.65,2.6,17.2,94,2.45,2.99,0.22,2.29,5.6,1.24,3.37,1265,0
|
||||
13.82,1.75,2.42,14,111,3.88,3.74,0.32,1.87,7.05,1.01,3.26,1190,0
|
||||
13.77,1.9,2.68,17.1,115,3,2.79,0.39,1.68,6.3,1.13,2.93,1375,0
|
||||
13.74,1.67,2.25,16.4,118,2.6,2.9,0.21,1.62,5.85,0.92,3.2,1060,0
|
||||
13.56,1.73,2.46,20.5,116,2.96,2.78,0.2,2.45,6.25,0.98,3.03,1120,0
|
||||
14.22,1.7,2.3,16.3,118,3.2,3,0.26,2.03,6.38,0.94,3.31,970,0
|
||||
13.29,1.97,2.68,16.8,102,3,3.23,0.31,1.66,6,1.07,2.84,1270,0
|
||||
13.72,1.43,2.5,16.7,108,3.4,3.67,0.19,2.04,6.8,0.89,2.87,1285,0
|
||||
12.37,0.94,1.36,10.6,88,1.98,0.57,0.28,0.42,1.95,1.05,1.82,520,1
|
||||
12.33,1.1,2.28,16,101,2.05,1.09,0.63,0.41,3.27,1.25,1.67,680,1
|
||||
12.64,1.36,2.02,16.8,100,2.02,1.41,0.53,0.62,5.75,0.98,1.59,450,1
|
||||
13.67,1.25,1.92,18,94,2.1,1.79,0.32,0.73,3.8,1.23,2.46,630,1
|
||||
12.37,1.13,2.16,19,87,3.5,3.1,0.19,1.87,4.45,1.22,2.87,420,1
|
||||
12.17,1.45,2.53,19,104,1.89,1.75,0.45,1.03,2.95,1.45,2.23,355,1
|
||||
12.37,1.21,2.56,18.1,98,2.42,2.65,0.37,2.08,4.6,1.19,2.3,678,1
|
||||
13.11,1.01,1.7,15,78,2.98,3.18,0.26,2.28,5.3,1.12,3.18,502,1
|
||||
12.37,1.17,1.92,19.6,78,2.11,2,0.27,1.04,4.68,1.12,3.48,510,1
|
||||
13.34,0.94,2.36,17,110,2.53,1.3,0.55,0.42,3.17,1.02,1.93,750,1
|
||||
12.21,1.19,1.75,16.8,151,1.85,1.28,0.14,2.5,2.85,1.28,3.07,718,1
|
||||
12.29,1.61,2.21,20.4,103,1.1,1.02,0.37,1.46,3.05,0.906,1.82,870,1
|
||||
13.86,1.51,2.67,25,86,2.95,2.86,0.21,1.87,3.38,1.36,3.16,410,1
|
||||
13.49,1.66,2.24,24,87,1.88,1.84,0.27,1.03,3.74,0.98,2.78,472,1
|
||||
12.99,1.67,2.6,30,139,3.3,2.89,0.21,1.96,3.35,1.31,3.5,985,1
|
||||
11.96,1.09,2.3,21,101,3.38,2.14,0.13,1.65,3.21,0.99,3.13,886,1
|
||||
11.66,1.88,1.92,16,97,1.61,1.57,0.34,1.15,3.8,1.23,2.14,428,1
|
||||
13.03,0.9,1.71,16,86,1.95,2.03,0.24,1.46,4.6,1.19,2.48,392,1
|
||||
11.84,2.89,2.23,18,112,1.72,1.32,0.43,0.95,2.65,0.96,2.52,500,1
|
||||
12.33,0.99,1.95,14.8,136,1.9,1.85,0.35,2.76,3.4,1.06,2.31,750,1
|
||||
12.7,3.87,2.4,23,101,2.83,2.55,0.43,1.95,2.57,1.19,3.13,463,1
|
||||
12,0.92,2,19,86,2.42,2.26,0.3,1.43,2.5,1.38,3.12,278,1
|
||||
12.72,1.81,2.2,18.8,86,2.2,2.53,0.26,1.77,3.9,1.16,3.14,714,1
|
||||
12.08,1.13,2.51,24,78,2,1.58,0.4,1.4,2.2,1.31,2.72,630,1
|
||||
13.05,3.86,2.32,22.5,85,1.65,1.59,0.61,1.62,4.8,0.84,2.01,515,1
|
||||
11.84,0.89,2.58,18,94,2.2,2.21,0.22,2.35,3.05,0.79,3.08,520,1
|
||||
12.67,0.98,2.24,18,99,2.2,1.94,0.3,1.46,2.62,1.23,3.16,450,1
|
||||
12.16,1.61,2.31,22.8,90,1.78,1.69,0.43,1.56,2.45,1.33,2.26,495,1
|
||||
11.65,1.67,2.62,26,88,1.92,1.61,0.4,1.34,2.6,1.36,3.21,562,1
|
||||
11.64,2.06,2.46,21.6,84,1.95,1.69,0.48,1.35,2.8,1,2.75,680,1
|
||||
12.08,1.33,2.3,23.6,70,2.2,1.59,0.42,1.38,1.74,1.07,3.21,625,1
|
||||
12.08,1.83,2.32,18.5,81,1.6,1.5,0.52,1.64,2.4,1.08,2.27,480,1
|
||||
12,1.51,2.42,22,86,1.45,1.25,0.5,1.63,3.6,1.05,2.65,450,1
|
||||
12.69,1.53,2.26,20.7,80,1.38,1.46,0.58,1.62,3.05,0.96,2.06,495,1
|
||||
12.29,2.83,2.22,18,88,2.45,2.25,0.25,1.99,2.15,1.15,3.3,290,1
|
||||
11.62,1.99,2.28,18,98,3.02,2.26,0.17,1.35,3.25,1.16,2.96,345,1
|
||||
12.47,1.52,2.2,19,162,2.5,2.27,0.32,3.28,2.6,1.16,2.63,937,1
|
||||
11.81,2.12,2.74,21.5,134,1.6,0.99,0.14,1.56,2.5,0.95,2.26,625,1
|
||||
12.29,1.41,1.98,16,85,2.55,2.5,0.29,1.77,2.9,1.23,2.74,428,1
|
||||
12.37,1.07,2.1,18.5,88,3.52,3.75,0.24,1.95,4.5,1.04,2.77,660,1
|
||||
12.29,3.17,2.21,18,88,2.85,2.99,0.45,2.81,2.3,1.42,2.83,406,1
|
||||
12.08,2.08,1.7,17.5,97,2.23,2.17,0.26,1.4,3.3,1.27,2.96,710,1
|
||||
12.6,1.34,1.9,18.5,88,1.45,1.36,0.29,1.35,2.45,1.04,2.77,562,1
|
||||
12.34,2.45,2.46,21,98,2.56,2.11,0.34,1.31,2.8,0.8,3.38,438,1
|
||||
11.82,1.72,1.88,19.5,86,2.5,1.64,0.37,1.42,2.06,0.94,2.44,415,1
|
||||
12.51,1.73,1.98,20.5,85,2.2,1.92,0.32,1.48,2.94,1.04,3.57,672,1
|
||||
12.42,2.55,2.27,22,90,1.68,1.84,0.66,1.42,2.7,0.86,3.3,315,1
|
||||
12.25,1.73,2.12,19,80,1.65,2.03,0.37,1.63,3.4,1,3.17,510,1
|
||||
12.72,1.75,2.28,22.5,84,1.38,1.76,0.48,1.63,3.3,0.88,2.42,488,1
|
||||
12.22,1.29,1.94,19,92,2.36,2.04,0.39,2.08,2.7,0.86,3.02,312,1
|
||||
11.61,1.35,2.7,20,94,2.74,2.92,0.29,2.49,2.65,0.96,3.26,680,1
|
||||
11.46,3.74,1.82,19.5,107,3.18,2.58,0.24,3.58,2.9,0.75,2.81,562,1
|
||||
12.52,2.43,2.17,21,88,2.55,2.27,0.26,1.22,2,0.9,2.78,325,1
|
||||
11.76,2.68,2.92,20,103,1.75,2.03,0.6,1.05,3.8,1.23,2.5,607,1
|
||||
11.41,0.74,2.5,21,88,2.48,2.01,0.42,1.44,3.08,1.1,2.31,434,1
|
||||
12.08,1.39,2.5,22.5,84,2.56,2.29,0.43,1.04,2.9,0.93,3.19,385,1
|
||||
11.03,1.51,2.2,21.5,85,2.46,2.17,0.52,2.01,1.9,1.71,2.87,407,1
|
||||
11.82,1.47,1.99,20.8,86,1.98,1.6,0.3,1.53,1.95,0.95,3.33,495,1
|
||||
12.42,1.61,2.19,22.5,108,2,2.09,0.34,1.61,2.06,1.06,2.96,345,1
|
||||
12.77,3.43,1.98,16,80,1.63,1.25,0.43,0.83,3.4,0.7,2.12,372,1
|
||||
12,3.43,2,19,87,2,1.64,0.37,1.87,1.28,0.93,3.05,564,1
|
||||
11.45,2.4,2.42,20,96,2.9,2.79,0.32,1.83,3.25,0.8,3.39,625,1
|
||||
11.56,2.05,3.23,28.5,119,3.18,5.08,0.47,1.87,6,0.93,3.69,465,1
|
||||
12.42,4.43,2.73,26.5,102,2.2,2.13,0.43,1.71,2.08,0.92,3.12,365,1
|
||||
13.05,5.8,2.13,21.5,86,2.62,2.65,0.3,2.01,2.6,0.73,3.1,380,1
|
||||
11.87,4.31,2.39,21,82,2.86,3.03,0.21,2.91,2.8,0.75,3.64,380,1
|
||||
12.07,2.16,2.17,21,85,2.6,2.65,0.37,1.35,2.76,0.86,3.28,378,1
|
||||
12.43,1.53,2.29,21.5,86,2.74,3.15,0.39,1.77,3.94,0.69,2.84,352,1
|
||||
11.79,2.13,2.78,28.5,92,2.13,2.24,0.58,1.76,3,0.97,2.44,466,1
|
||||
12.37,1.63,2.3,24.5,88,2.22,2.45,0.4,1.9,2.12,0.89,2.78,342,1
|
||||
12.04,4.3,2.38,22,80,2.1,1.75,0.42,1.35,2.6,0.79,2.57,580,1
|
||||
12.86,1.35,2.32,18,122,1.51,1.25,0.21,0.94,4.1,0.76,1.29,630,2
|
||||
12.88,2.99,2.4,20,104,1.3,1.22,0.24,0.83,5.4,0.74,1.42,530,2
|
||||
12.81,2.31,2.4,24,98,1.15,1.09,0.27,0.83,5.7,0.66,1.36,560,2
|
||||
12.7,3.55,2.36,21.5,106,1.7,1.2,0.17,0.84,5,0.78,1.29,600,2
|
||||
12.51,1.24,2.25,17.5,85,2,0.58,0.6,1.25,5.45,0.75,1.51,650,2
|
||||
12.6,2.46,2.2,18.5,94,1.62,0.66,0.63,0.94,7.1,0.73,1.58,695,2
|
||||
12.25,4.72,2.54,21,89,1.38,0.47,0.53,0.8,3.85,0.75,1.27,720,2
|
||||
12.53,5.51,2.64,25,96,1.79,0.6,0.63,1.1,5,0.82,1.69,515,2
|
||||
13.49,3.59,2.19,19.5,88,1.62,0.48,0.58,0.88,5.7,0.81,1.82,580,2
|
||||
12.84,2.96,2.61,24,101,2.32,0.6,0.53,0.81,4.92,0.89,2.15,590,2
|
||||
12.93,2.81,2.7,21,96,1.54,0.5,0.53,0.75,4.6,0.77,2.31,600,2
|
||||
13.36,2.56,2.35,20,89,1.4,0.5,0.37,0.64,5.6,0.7,2.47,780,2
|
||||
13.52,3.17,2.72,23.5,97,1.55,0.52,0.5,0.55,4.35,0.89,2.06,520,2
|
||||
13.62,4.95,2.35,20,92,2,0.8,0.47,1.02,4.4,0.91,2.05,550,2
|
||||
12.25,3.88,2.2,18.5,112,1.38,0.78,0.29,1.14,8.21,0.65,2,855,2
|
||||
13.16,3.57,2.15,21,102,1.5,0.55,0.43,1.3,4,0.6,1.68,830,2
|
||||
13.88,5.04,2.23,20,80,0.98,0.34,0.4,0.68,4.9,0.58,1.33,415,2
|
||||
12.87,4.61,2.48,21.5,86,1.7,0.65,0.47,0.86,7.65,0.54,1.86,625,2
|
||||
13.32,3.24,2.38,21.5,92,1.93,0.76,0.45,1.25,8.42,0.55,1.62,650,2
|
||||
13.08,3.9,2.36,21.5,113,1.41,1.39,0.34,1.14,9.4,0.57,1.33,550,2
|
||||
13.5,3.12,2.62,24,123,1.4,1.57,0.22,1.25,8.6,0.59,1.3,500,2
|
||||
12.79,2.67,2.48,22,112,1.48,1.36,0.24,1.26,10.8,0.48,1.47,480,2
|
||||
13.11,1.9,2.75,25.5,116,2.2,1.28,0.26,1.56,7.1,0.61,1.33,425,2
|
||||
13.23,3.3,2.28,18.5,98,1.8,0.83,0.61,1.87,10.52,0.56,1.51,675,2
|
||||
12.58,1.29,2.1,20,103,1.48,0.58,0.53,1.4,7.6,0.58,1.55,640,2
|
||||
13.17,5.19,2.32,22,93,1.74,0.63,0.61,1.55,7.9,0.6,1.48,725,2
|
||||
13.84,4.12,2.38,19.5,89,1.8,0.83,0.48,1.56,9.01,0.57,1.64,480,2
|
||||
12.45,3.03,2.64,27,97,1.9,0.58,0.63,1.14,7.5,0.67,1.73,880,2
|
||||
14.34,1.68,2.7,25,98,2.8,1.31,0.53,2.7,13,0.57,1.96,660,2
|
||||
13.48,1.67,2.64,22.5,89,2.6,1.1,0.52,2.29,11.75,0.57,1.78,620,2
|
||||
12.36,3.83,2.38,21,88,2.3,0.92,0.5,1.04,7.65,0.56,1.58,520,2
|
||||
13.69,3.26,2.54,20,107,1.83,0.56,0.5,0.8,5.88,0.96,1.82,680,2
|
||||
12.85,3.27,2.58,22,106,1.65,0.6,0.6,0.96,5.58,0.87,2.11,570,2
|
||||
12.96,3.45,2.35,18.5,106,1.39,0.7,0.4,0.94,5.28,0.68,1.75,675,2
|
||||
13.78,2.76,2.3,22,90,1.35,0.68,0.41,1.03,9.58,0.7,1.68,615,2
|
||||
13.73,4.36,2.26,22.5,88,1.28,0.47,0.52,1.15,6.62,0.78,1.75,520,2
|
||||
13.45,3.7,2.6,23,111,1.7,0.92,0.43,1.46,10.68,0.85,1.56,695,2
|
||||
12.82,3.37,2.3,19.5,88,1.48,0.66,0.4,0.97,10.26,0.72,1.75,685,2
|
||||
13.58,2.58,2.69,24.5,105,1.55,0.84,0.39,1.54,8.66,0.74,1.8,750,2
|
||||
13.4,4.6,2.86,25,112,1.98,0.96,0.27,1.11,8.5,0.67,1.92,630,2
|
||||
12.2,3.03,2.32,19,96,1.25,0.49,0.4,0.73,5.5,0.66,1.83,510,2
|
||||
12.77,2.39,2.28,19.5,86,1.39,0.51,0.48,0.64,9.899999,0.57,1.63,470,2
|
||||
14.16,2.51,2.48,20,91,1.68,0.7,0.44,1.24,9.7,0.62,1.71,660,2
|
||||
13.71,5.65,2.45,20.5,95,1.68,0.61,0.52,1.06,7.7,0.64,1.74,740,2
|
||||
13.4,3.91,2.48,23,102,1.8,0.75,0.43,1.41,7.3,0.7,1.56,750,2
|
||||
13.27,4.28,2.26,20,120,1.59,0.69,0.43,1.35,10.2,0.59,1.56,835,2
|
||||
13.17,2.59,2.37,20,120,1.65,0.68,0.53,1.46,9.3,0.6,1.62,840,2
|
||||
14.13,4.1,2.74,24.5,96,2.05,0.76,0.56,1.35,9.2,0.61,1.6,560,2
|
||||
|
||||
|
+118
-118
@@ -1,118 +1,118 @@
|
||||
.. _breast_cancer_dataset:
|
||||
|
||||
Breast cancer Wisconsin (diagnostic) dataset
|
||||
--------------------------------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 569
|
||||
|
||||
:Number of Attributes: 30 numeric, predictive attributes and the class
|
||||
|
||||
:Attribute Information:
|
||||
- radius (mean of distances from center to points on the perimeter)
|
||||
- texture (standard deviation of gray-scale values)
|
||||
- perimeter
|
||||
- area
|
||||
- smoothness (local variation in radius lengths)
|
||||
- compactness (perimeter^2 / area - 1.0)
|
||||
- concavity (severity of concave portions of the contour)
|
||||
- concave points (number of concave portions of the contour)
|
||||
- symmetry
|
||||
- fractal dimension ("coastline approximation" - 1)
|
||||
|
||||
The mean, standard error, and "worst" or largest (mean of the three
|
||||
worst/largest values) of these features were computed for each image,
|
||||
resulting in 30 features. For instance, field 0 is Mean Radius, field
|
||||
10 is Radius SE, field 20 is Worst Radius.
|
||||
|
||||
- class:
|
||||
- WDBC-Malignant
|
||||
- WDBC-Benign
|
||||
|
||||
:Summary Statistics:
|
||||
|
||||
===================================== ====== ======
|
||||
Min Max
|
||||
===================================== ====== ======
|
||||
radius (mean): 6.981 28.11
|
||||
texture (mean): 9.71 39.28
|
||||
perimeter (mean): 43.79 188.5
|
||||
area (mean): 143.5 2501.0
|
||||
smoothness (mean): 0.053 0.163
|
||||
compactness (mean): 0.019 0.345
|
||||
concavity (mean): 0.0 0.427
|
||||
concave points (mean): 0.0 0.201
|
||||
symmetry (mean): 0.106 0.304
|
||||
fractal dimension (mean): 0.05 0.097
|
||||
radius (standard error): 0.112 2.873
|
||||
texture (standard error): 0.36 4.885
|
||||
perimeter (standard error): 0.757 21.98
|
||||
area (standard error): 6.802 542.2
|
||||
smoothness (standard error): 0.002 0.031
|
||||
compactness (standard error): 0.002 0.135
|
||||
concavity (standard error): 0.0 0.396
|
||||
concave points (standard error): 0.0 0.053
|
||||
symmetry (standard error): 0.008 0.079
|
||||
fractal dimension (standard error): 0.001 0.03
|
||||
radius (worst): 7.93 36.04
|
||||
texture (worst): 12.02 49.54
|
||||
perimeter (worst): 50.41 251.2
|
||||
area (worst): 185.2 4254.0
|
||||
smoothness (worst): 0.071 0.223
|
||||
compactness (worst): 0.027 1.058
|
||||
concavity (worst): 0.0 1.252
|
||||
concave points (worst): 0.0 0.291
|
||||
symmetry (worst): 0.156 0.664
|
||||
fractal dimension (worst): 0.055 0.208
|
||||
===================================== ====== ======
|
||||
|
||||
:Missing Attribute Values: None
|
||||
|
||||
:Class Distribution: 212 - Malignant, 357 - Benign
|
||||
|
||||
:Creator: Dr. William H. Wolberg, W. Nick Street, Olvi L. Mangasarian
|
||||
|
||||
:Donor: Nick Street
|
||||
|
||||
:Date: November, 1995
|
||||
|
||||
This is a copy of UCI ML Breast Cancer Wisconsin (Diagnostic) datasets.
|
||||
https://goo.gl/U2Uwz2
|
||||
|
||||
Features are computed from a digitized image of a fine needle
|
||||
aspirate (FNA) of a breast mass. They describe
|
||||
characteristics of the cell nuclei present in the image.
|
||||
|
||||
Separating plane described above was obtained using
|
||||
Multisurface Method-Tree (MSM-T) [K. P. Bennett, "Decision Tree
|
||||
Construction Via Linear Programming." Proceedings of the 4th
|
||||
Midwest Artificial Intelligence and Cognitive Science Society,
|
||||
pp. 97-101, 1992], a classification method which uses linear
|
||||
programming to construct a decision tree. Relevant features
|
||||
were selected using an exhaustive search in the space of 1-4
|
||||
features and 1-3 separating planes.
|
||||
|
||||
The actual linear program used to obtain the separating plane
|
||||
in the 3-dimensional space is that described in:
|
||||
[K. P. Bennett and O. L. Mangasarian: "Robust Linear
|
||||
Programming Discrimination of Two Linearly Inseparable Sets",
|
||||
Optimization Methods and Software 1, 1992, 23-34].
|
||||
|
||||
This database is also available through the UW CS ftp server:
|
||||
|
||||
ftp ftp.cs.wisc.edu
|
||||
cd math-prog/cpo-dataset/machine-learn/WDBC/
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
- W.N. Street, W.H. Wolberg and O.L. Mangasarian. Nuclear feature extraction
|
||||
for breast tumor diagnosis. IS&T/SPIE 1993 International Symposium on
|
||||
Electronic Imaging: Science and Technology, volume 1905, pages 861-870,
|
||||
San Jose, CA, 1993.
|
||||
- O.L. Mangasarian, W.N. Street and W.H. Wolberg. Breast cancer diagnosis and
|
||||
prognosis via linear programming. Operations Research, 43(4), pages 570-577,
|
||||
July-August 1995.
|
||||
- W.H. Wolberg, W.N. Street, and O.L. Mangasarian. Machine learning techniques
|
||||
to diagnose breast cancer from fine-needle aspirates. Cancer Letters 77 (1994)
|
||||
163-171.
|
||||
.. _breast_cancer_dataset:
|
||||
|
||||
Breast cancer Wisconsin (diagnostic) dataset
|
||||
--------------------------------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 569
|
||||
|
||||
:Number of Attributes: 30 numeric, predictive attributes and the class
|
||||
|
||||
:Attribute Information:
|
||||
- radius (mean of distances from center to points on the perimeter)
|
||||
- texture (standard deviation of gray-scale values)
|
||||
- perimeter
|
||||
- area
|
||||
- smoothness (local variation in radius lengths)
|
||||
- compactness (perimeter^2 / area - 1.0)
|
||||
- concavity (severity of concave portions of the contour)
|
||||
- concave points (number of concave portions of the contour)
|
||||
- symmetry
|
||||
- fractal dimension ("coastline approximation" - 1)
|
||||
|
||||
The mean, standard error, and "worst" or largest (mean of the three
|
||||
worst/largest values) of these features were computed for each image,
|
||||
resulting in 30 features. For instance, field 0 is Mean Radius, field
|
||||
10 is Radius SE, field 20 is Worst Radius.
|
||||
|
||||
- class:
|
||||
- WDBC-Malignant
|
||||
- WDBC-Benign
|
||||
|
||||
:Summary Statistics:
|
||||
|
||||
===================================== ====== ======
|
||||
Min Max
|
||||
===================================== ====== ======
|
||||
radius (mean): 6.981 28.11
|
||||
texture (mean): 9.71 39.28
|
||||
perimeter (mean): 43.79 188.5
|
||||
area (mean): 143.5 2501.0
|
||||
smoothness (mean): 0.053 0.163
|
||||
compactness (mean): 0.019 0.345
|
||||
concavity (mean): 0.0 0.427
|
||||
concave points (mean): 0.0 0.201
|
||||
symmetry (mean): 0.106 0.304
|
||||
fractal dimension (mean): 0.05 0.097
|
||||
radius (standard error): 0.112 2.873
|
||||
texture (standard error): 0.36 4.885
|
||||
perimeter (standard error): 0.757 21.98
|
||||
area (standard error): 6.802 542.2
|
||||
smoothness (standard error): 0.002 0.031
|
||||
compactness (standard error): 0.002 0.135
|
||||
concavity (standard error): 0.0 0.396
|
||||
concave points (standard error): 0.0 0.053
|
||||
symmetry (standard error): 0.008 0.079
|
||||
fractal dimension (standard error): 0.001 0.03
|
||||
radius (worst): 7.93 36.04
|
||||
texture (worst): 12.02 49.54
|
||||
perimeter (worst): 50.41 251.2
|
||||
area (worst): 185.2 4254.0
|
||||
smoothness (worst): 0.071 0.223
|
||||
compactness (worst): 0.027 1.058
|
||||
concavity (worst): 0.0 1.252
|
||||
concave points (worst): 0.0 0.291
|
||||
symmetry (worst): 0.156 0.664
|
||||
fractal dimension (worst): 0.055 0.208
|
||||
===================================== ====== ======
|
||||
|
||||
:Missing Attribute Values: None
|
||||
|
||||
:Class Distribution: 212 - Malignant, 357 - Benign
|
||||
|
||||
:Creator: Dr. William H. Wolberg, W. Nick Street, Olvi L. Mangasarian
|
||||
|
||||
:Donor: Nick Street
|
||||
|
||||
:Date: November, 1995
|
||||
|
||||
This is a copy of UCI ML Breast Cancer Wisconsin (Diagnostic) datasets.
|
||||
https://goo.gl/U2Uwz2
|
||||
|
||||
Features are computed from a digitized image of a fine needle
|
||||
aspirate (FNA) of a breast mass. They describe
|
||||
characteristics of the cell nuclei present in the image.
|
||||
|
||||
Separating plane described above was obtained using
|
||||
Multisurface Method-Tree (MSM-T) [K. P. Bennett, "Decision Tree
|
||||
Construction Via Linear Programming." Proceedings of the 4th
|
||||
Midwest Artificial Intelligence and Cognitive Science Society,
|
||||
pp. 97-101, 1992], a classification method which uses linear
|
||||
programming to construct a decision tree. Relevant features
|
||||
were selected using an exhaustive search in the space of 1-4
|
||||
features and 1-3 separating planes.
|
||||
|
||||
The actual linear program used to obtain the separating plane
|
||||
in the 3-dimensional space is that described in:
|
||||
[K. P. Bennett and O. L. Mangasarian: "Robust Linear
|
||||
Programming Discrimination of Two Linearly Inseparable Sets",
|
||||
Optimization Methods and Software 1, 1992, 23-34].
|
||||
|
||||
This database is also available through the UW CS ftp server:
|
||||
|
||||
ftp ftp.cs.wisc.edu
|
||||
cd math-prog/cpo-dataset/machine-learn/WDBC/
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
- W.N. Street, W.H. Wolberg and O.L. Mangasarian. Nuclear feature extraction
|
||||
for breast tumor diagnosis. IS&T/SPIE 1993 International Symposium on
|
||||
Electronic Imaging: Science and Technology, volume 1905, pages 861-870,
|
||||
San Jose, CA, 1993.
|
||||
- O.L. Mangasarian, W.N. Street and W.H. Wolberg. Breast cancer diagnosis and
|
||||
prognosis via linear programming. Operations Research, 43(4), pages 570-577,
|
||||
July-August 1995.
|
||||
- W.H. Wolberg, W.N. Street, and O.L. Mangasarian. Machine learning techniques
|
||||
to diagnose breast cancer from fine-needle aspirates. Cancer Letters 77 (1994)
|
||||
163-171.
|
||||
|
||||
+46
-46
@@ -1,46 +1,46 @@
|
||||
.. _california_housing_dataset:
|
||||
|
||||
California Housing dataset
|
||||
--------------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 20640
|
||||
|
||||
:Number of Attributes: 8 numeric, predictive attributes and the target
|
||||
|
||||
:Attribute Information:
|
||||
- MedInc median income in block group
|
||||
- HouseAge median house age in block group
|
||||
- AveRooms average number of rooms per household
|
||||
- AveBedrms average number of bedrooms per household
|
||||
- Population block group population
|
||||
- AveOccup average number of household members
|
||||
- Latitude block group latitude
|
||||
- Longitude block group longitude
|
||||
|
||||
:Missing Attribute Values: None
|
||||
|
||||
This dataset was obtained from the StatLib repository.
|
||||
https://www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.html
|
||||
|
||||
The target variable is the median house value for California districts,
|
||||
expressed in hundreds of thousands of dollars ($100,000).
|
||||
|
||||
This dataset was derived from the 1990 U.S. census, using one row per census
|
||||
block group. A block group is the smallest geographical unit for which the U.S.
|
||||
Census Bureau publishes sample data (a block group typically has a population
|
||||
of 600 to 3,000 people).
|
||||
|
||||
A household is a group of people residing within a home. Since the average
|
||||
number of rooms and bedrooms in this dataset are provided per household, these
|
||||
columns may take surprisingly large values for block groups with few households
|
||||
and many empty houses, such as vacation resorts.
|
||||
|
||||
It can be downloaded/loaded using the
|
||||
:func:`sklearn.datasets.fetch_california_housing` function.
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
- Pace, R. Kelley and Ronald Barry, Sparse Spatial Autoregressions,
|
||||
Statistics and Probability Letters, 33:291-297, 1997.
|
||||
.. _california_housing_dataset:
|
||||
|
||||
California Housing dataset
|
||||
--------------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 20640
|
||||
|
||||
:Number of Attributes: 8 numeric, predictive attributes and the target
|
||||
|
||||
:Attribute Information:
|
||||
- MedInc median income in block group
|
||||
- HouseAge median house age in block group
|
||||
- AveRooms average number of rooms per household
|
||||
- AveBedrms average number of bedrooms per household
|
||||
- Population block group population
|
||||
- AveOccup average number of household members
|
||||
- Latitude block group latitude
|
||||
- Longitude block group longitude
|
||||
|
||||
:Missing Attribute Values: None
|
||||
|
||||
This dataset was obtained from the StatLib repository.
|
||||
https://www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.html
|
||||
|
||||
The target variable is the median house value for California districts,
|
||||
expressed in hundreds of thousands of dollars ($100,000).
|
||||
|
||||
This dataset was derived from the 1990 U.S. census, using one row per census
|
||||
block group. A block group is the smallest geographical unit for which the U.S.
|
||||
Census Bureau publishes sample data (a block group typically has a population
|
||||
of 600 to 3,000 people).
|
||||
|
||||
A household is a group of people residing within a home. Since the average
|
||||
number of rooms and bedrooms in this dataset are provided per household, these
|
||||
columns may take surprisingly large values for block groups with few households
|
||||
and many empty houses, such as vacation resorts.
|
||||
|
||||
It can be downloaded/loaded using the
|
||||
:func:`sklearn.datasets.fetch_california_housing` function.
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
- Pace, R. Kelley and Ronald Barry, Sparse Spatial Autoregressions,
|
||||
Statistics and Probability Letters, 33:291-297, 1997.
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
.. _covtype_dataset:
|
||||
|
||||
Forest covertypes
|
||||
-----------------
|
||||
|
||||
The samples in this dataset correspond to 30×30m patches of forest in the US,
|
||||
collected for the task of predicting each patch's cover type,
|
||||
i.e. the dominant species of tree.
|
||||
There are seven covertypes, making this a multiclass classification problem.
|
||||
Each sample has 54 features, described on the
|
||||
`dataset's homepage <https://archive.ics.uci.edu/ml/datasets/Covertype>`__.
|
||||
Some of the features are boolean indicators,
|
||||
while others are discrete or continuous measurements.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
================= ============
|
||||
Classes 7
|
||||
Samples total 581012
|
||||
Dimensionality 54
|
||||
Features int
|
||||
================= ============
|
||||
|
||||
:func:`sklearn.datasets.fetch_covtype` will load the covertype dataset;
|
||||
it returns a dictionary-like 'Bunch' object
|
||||
with the feature matrix in the ``data`` member
|
||||
and the target values in ``target``. If optional argument 'as_frame' is
|
||||
set to 'True', it will return ``data`` and ``target`` as pandas
|
||||
data frame, and there will be an additional member ``frame`` as well.
|
||||
The dataset will be downloaded from the web if necessary.
|
||||
.. _covtype_dataset:
|
||||
|
||||
Forest covertypes
|
||||
-----------------
|
||||
|
||||
The samples in this dataset correspond to 30×30m patches of forest in the US,
|
||||
collected for the task of predicting each patch's cover type,
|
||||
i.e. the dominant species of tree.
|
||||
There are seven covertypes, making this a multiclass classification problem.
|
||||
Each sample has 54 features, described on the
|
||||
`dataset's homepage <https://archive.ics.uci.edu/ml/datasets/Covertype>`__.
|
||||
Some of the features are boolean indicators,
|
||||
while others are discrete or continuous measurements.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
================= ============
|
||||
Classes 7
|
||||
Samples total 581012
|
||||
Dimensionality 54
|
||||
Features int
|
||||
================= ============
|
||||
|
||||
:func:`sklearn.datasets.fetch_covtype` will load the covertype dataset;
|
||||
it returns a dictionary-like 'Bunch' object
|
||||
with the feature matrix in the ``data`` member
|
||||
and the target values in ``target``. If optional argument 'as_frame' is
|
||||
set to 'True', it will return ``data`` and ``target`` as pandas
|
||||
data frame, and there will be an additional member ``frame`` as well.
|
||||
The dataset will be downloaded from the web if necessary.
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
.. _diabetes_dataset:
|
||||
|
||||
Diabetes dataset
|
||||
----------------
|
||||
|
||||
Ten baseline variables, age, sex, body mass index, average blood
|
||||
pressure, and six blood serum measurements were obtained for each of n =
|
||||
442 diabetes patients, as well as the response of interest, a
|
||||
quantitative measure of disease progression one year after baseline.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 442
|
||||
|
||||
:Number of Attributes: First 10 columns are numeric predictive values
|
||||
|
||||
:Target: Column 11 is a quantitative measure of disease progression one year after baseline
|
||||
|
||||
:Attribute Information:
|
||||
- age age in years
|
||||
- sex
|
||||
- bmi body mass index
|
||||
- bp average blood pressure
|
||||
- s1 tc, total serum cholesterol
|
||||
- s2 ldl, low-density lipoproteins
|
||||
- s3 hdl, high-density lipoproteins
|
||||
- s4 tch, total cholesterol / HDL
|
||||
- s5 ltg, possibly log of serum triglycerides level
|
||||
- s6 glu, blood sugar level
|
||||
|
||||
Note: Each of these 10 feature variables have been mean centered and scaled by the standard deviation times the square root of `n_samples` (i.e. the sum of squares of each column totals 1).
|
||||
|
||||
Source URL:
|
||||
https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html
|
||||
|
||||
For more information see:
|
||||
Bradley Efron, Trevor Hastie, Iain Johnstone and Robert Tibshirani (2004) "Least Angle Regression," Annals of Statistics (with discussion), 407-499.
|
||||
(https://web.stanford.edu/~hastie/Papers/LARS/LeastAngle_2002.pdf)
|
||||
.. _diabetes_dataset:
|
||||
|
||||
Diabetes dataset
|
||||
----------------
|
||||
|
||||
Ten baseline variables, age, sex, body mass index, average blood
|
||||
pressure, and six blood serum measurements were obtained for each of n =
|
||||
442 diabetes patients, as well as the response of interest, a
|
||||
quantitative measure of disease progression one year after baseline.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 442
|
||||
|
||||
:Number of Attributes: First 10 columns are numeric predictive values
|
||||
|
||||
:Target: Column 11 is a quantitative measure of disease progression one year after baseline
|
||||
|
||||
:Attribute Information:
|
||||
- age age in years
|
||||
- sex
|
||||
- bmi body mass index
|
||||
- bp average blood pressure
|
||||
- s1 tc, total serum cholesterol
|
||||
- s2 ldl, low-density lipoproteins
|
||||
- s3 hdl, high-density lipoproteins
|
||||
- s4 tch, total cholesterol / HDL
|
||||
- s5 ltg, possibly log of serum triglycerides level
|
||||
- s6 glu, blood sugar level
|
||||
|
||||
Note: Each of these 10 feature variables have been mean centered and scaled by the standard deviation times the square root of `n_samples` (i.e. the sum of squares of each column totals 1).
|
||||
|
||||
Source URL:
|
||||
https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html
|
||||
|
||||
For more information see:
|
||||
Bradley Efron, Trevor Hastie, Iain Johnstone and Robert Tibshirani (2004) "Least Angle Regression," Annals of Statistics (with discussion), 407-499.
|
||||
(https://web.stanford.edu/~hastie/Papers/LARS/LeastAngle_2002.pdf)
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
.. _digits_dataset:
|
||||
|
||||
Optical recognition of handwritten digits dataset
|
||||
--------------------------------------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 1797
|
||||
:Number of Attributes: 64
|
||||
:Attribute Information: 8x8 image of integer pixels in the range 0..16.
|
||||
:Missing Attribute Values: None
|
||||
:Creator: E. Alpaydin (alpaydin '@' boun.edu.tr)
|
||||
:Date: July; 1998
|
||||
|
||||
This is a copy of the test set of the UCI ML hand-written digits datasets
|
||||
https://archive.ics.uci.edu/ml/datasets/Optical+Recognition+of+Handwritten+Digits
|
||||
|
||||
The data set contains images of hand-written digits: 10 classes where
|
||||
each class refers to a digit.
|
||||
|
||||
Preprocessing programs made available by NIST were used to extract
|
||||
normalized bitmaps of handwritten digits from a preprinted form. From a
|
||||
total of 43 people, 30 contributed to the training set and different 13
|
||||
to the test set. 32x32 bitmaps are divided into nonoverlapping blocks of
|
||||
4x4 and the number of on pixels are counted in each block. This generates
|
||||
an input matrix of 8x8 where each element is an integer in the range
|
||||
0..16. This reduces dimensionality and gives invariance to small
|
||||
distortions.
|
||||
|
||||
For info on NIST preprocessing routines, see M. D. Garris, J. L. Blue, G.
|
||||
T. Candela, D. L. Dimmick, J. Geist, P. J. Grother, S. A. Janet, and C.
|
||||
L. Wilson, NIST Form-Based Handprint Recognition System, NISTIR 5469,
|
||||
1994.
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
- C. Kaynak (1995) Methods of Combining Multiple Classifiers and Their
|
||||
Applications to Handwritten Digit Recognition, MSc Thesis, Institute of
|
||||
Graduate Studies in Science and Engineering, Bogazici University.
|
||||
- E. Alpaydin, C. Kaynak (1998) Cascading Classifiers, Kybernetika.
|
||||
- Ken Tang and Ponnuthurai N. Suganthan and Xi Yao and A. Kai Qin.
|
||||
Linear dimensionalityreduction using relevance weighted LDA. School of
|
||||
Electrical and Electronic Engineering Nanyang Technological University.
|
||||
2005.
|
||||
- Claudio Gentile. A New Approximate Maximal Margin Classification
|
||||
Algorithm. NIPS. 2000.
|
||||
.. _digits_dataset:
|
||||
|
||||
Optical recognition of handwritten digits dataset
|
||||
--------------------------------------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 1797
|
||||
:Number of Attributes: 64
|
||||
:Attribute Information: 8x8 image of integer pixels in the range 0..16.
|
||||
:Missing Attribute Values: None
|
||||
:Creator: E. Alpaydin (alpaydin '@' boun.edu.tr)
|
||||
:Date: July; 1998
|
||||
|
||||
This is a copy of the test set of the UCI ML hand-written digits datasets
|
||||
https://archive.ics.uci.edu/ml/datasets/Optical+Recognition+of+Handwritten+Digits
|
||||
|
||||
The data set contains images of hand-written digits: 10 classes where
|
||||
each class refers to a digit.
|
||||
|
||||
Preprocessing programs made available by NIST were used to extract
|
||||
normalized bitmaps of handwritten digits from a preprinted form. From a
|
||||
total of 43 people, 30 contributed to the training set and different 13
|
||||
to the test set. 32x32 bitmaps are divided into nonoverlapping blocks of
|
||||
4x4 and the number of on pixels are counted in each block. This generates
|
||||
an input matrix of 8x8 where each element is an integer in the range
|
||||
0..16. This reduces dimensionality and gives invariance to small
|
||||
distortions.
|
||||
|
||||
For info on NIST preprocessing routines, see M. D. Garris, J. L. Blue, G.
|
||||
T. Candela, D. L. Dimmick, J. Geist, P. J. Grother, S. A. Janet, and C.
|
||||
L. Wilson, NIST Form-Based Handprint Recognition System, NISTIR 5469,
|
||||
1994.
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
- C. Kaynak (1995) Methods of Combining Multiple Classifiers and Their
|
||||
Applications to Handwritten Digit Recognition, MSc Thesis, Institute of
|
||||
Graduate Studies in Science and Engineering, Bogazici University.
|
||||
- E. Alpaydin, C. Kaynak (1998) Cascading Classifiers, Kybernetika.
|
||||
- Ken Tang and Ponnuthurai N. Suganthan and Xi Yao and A. Kai Qin.
|
||||
Linear dimensionalityreduction using relevance weighted LDA. School of
|
||||
Electrical and Electronic Engineering Nanyang Technological University.
|
||||
2005.
|
||||
- Claudio Gentile. A New Approximate Maximal Margin Classification
|
||||
Algorithm. NIPS. 2000.
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
.. _iris_dataset:
|
||||
|
||||
Iris plants dataset
|
||||
--------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 150 (50 in each of three classes)
|
||||
:Number of Attributes: 4 numeric, predictive attributes and the class
|
||||
:Attribute Information:
|
||||
- sepal length in cm
|
||||
- sepal width in cm
|
||||
- petal length in cm
|
||||
- petal width in cm
|
||||
- class:
|
||||
- Iris-Setosa
|
||||
- Iris-Versicolour
|
||||
- Iris-Virginica
|
||||
|
||||
:Summary Statistics:
|
||||
|
||||
============== ==== ==== ======= ===== ====================
|
||||
Min Max Mean SD Class Correlation
|
||||
============== ==== ==== ======= ===== ====================
|
||||
sepal length: 4.3 7.9 5.84 0.83 0.7826
|
||||
sepal width: 2.0 4.4 3.05 0.43 -0.4194
|
||||
petal length: 1.0 6.9 3.76 1.76 0.9490 (high!)
|
||||
petal width: 0.1 2.5 1.20 0.76 0.9565 (high!)
|
||||
============== ==== ==== ======= ===== ====================
|
||||
|
||||
:Missing Attribute Values: None
|
||||
:Class Distribution: 33.3% for each of 3 classes.
|
||||
:Creator: R.A. Fisher
|
||||
:Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)
|
||||
:Date: July, 1988
|
||||
|
||||
The famous Iris database, first used by Sir R.A. Fisher. The dataset is taken
|
||||
from Fisher's paper. Note that it's the same as in R, but not as in the UCI
|
||||
Machine Learning Repository, which has two wrong data points.
|
||||
|
||||
This is perhaps the best known database to be found in the
|
||||
pattern recognition literature. Fisher's paper is a classic in the field and
|
||||
is referenced frequently to this day. (See Duda & Hart, for example.) The
|
||||
data set contains 3 classes of 50 instances each, where each class refers to a
|
||||
type of iris plant. One class is linearly separable from the other 2; the
|
||||
latter are NOT linearly separable from each other.
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
- Fisher, R.A. "The use of multiple measurements in taxonomic problems"
|
||||
Annual Eugenics, 7, Part II, 179-188 (1936); also in "Contributions to
|
||||
Mathematical Statistics" (John Wiley, NY, 1950).
|
||||
- Duda, R.O., & Hart, P.E. (1973) Pattern Classification and Scene Analysis.
|
||||
(Q327.D83) John Wiley & Sons. ISBN 0-471-22361-1. See page 218.
|
||||
- Dasarathy, B.V. (1980) "Nosing Around the Neighborhood: A New System
|
||||
Structure and Classification Rule for Recognition in Partially Exposed
|
||||
Environments". IEEE Transactions on Pattern Analysis and Machine
|
||||
Intelligence, Vol. PAMI-2, No. 1, 67-71.
|
||||
- Gates, G.W. (1972) "The Reduced Nearest Neighbor Rule". IEEE Transactions
|
||||
on Information Theory, May 1972, 431-433.
|
||||
- See also: 1988 MLC Proceedings, 54-64. Cheeseman et al"s AUTOCLASS II
|
||||
conceptual clustering system finds 3 classes in the data.
|
||||
- Many, many more ...
|
||||
.. _iris_dataset:
|
||||
|
||||
Iris plants dataset
|
||||
--------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 150 (50 in each of three classes)
|
||||
:Number of Attributes: 4 numeric, predictive attributes and the class
|
||||
:Attribute Information:
|
||||
- sepal length in cm
|
||||
- sepal width in cm
|
||||
- petal length in cm
|
||||
- petal width in cm
|
||||
- class:
|
||||
- Iris-Setosa
|
||||
- Iris-Versicolour
|
||||
- Iris-Virginica
|
||||
|
||||
:Summary Statistics:
|
||||
|
||||
============== ==== ==== ======= ===== ====================
|
||||
Min Max Mean SD Class Correlation
|
||||
============== ==== ==== ======= ===== ====================
|
||||
sepal length: 4.3 7.9 5.84 0.83 0.7826
|
||||
sepal width: 2.0 4.4 3.05 0.43 -0.4194
|
||||
petal length: 1.0 6.9 3.76 1.76 0.9490 (high!)
|
||||
petal width: 0.1 2.5 1.20 0.76 0.9565 (high!)
|
||||
============== ==== ==== ======= ===== ====================
|
||||
|
||||
:Missing Attribute Values: None
|
||||
:Class Distribution: 33.3% for each of 3 classes.
|
||||
:Creator: R.A. Fisher
|
||||
:Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)
|
||||
:Date: July, 1988
|
||||
|
||||
The famous Iris database, first used by Sir R.A. Fisher. The dataset is taken
|
||||
from Fisher's paper. Note that it's the same as in R, but not as in the UCI
|
||||
Machine Learning Repository, which has two wrong data points.
|
||||
|
||||
This is perhaps the best known database to be found in the
|
||||
pattern recognition literature. Fisher's paper is a classic in the field and
|
||||
is referenced frequently to this day. (See Duda & Hart, for example.) The
|
||||
data set contains 3 classes of 50 instances each, where each class refers to a
|
||||
type of iris plant. One class is linearly separable from the other 2; the
|
||||
latter are NOT linearly separable from each other.
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
- Fisher, R.A. "The use of multiple measurements in taxonomic problems"
|
||||
Annual Eugenics, 7, Part II, 179-188 (1936); also in "Contributions to
|
||||
Mathematical Statistics" (John Wiley, NY, 1950).
|
||||
- Duda, R.O., & Hart, P.E. (1973) Pattern Classification and Scene Analysis.
|
||||
(Q327.D83) John Wiley & Sons. ISBN 0-471-22361-1. See page 218.
|
||||
- Dasarathy, B.V. (1980) "Nosing Around the Neighborhood: A New System
|
||||
Structure and Classification Rule for Recognition in Partially Exposed
|
||||
Environments". IEEE Transactions on Pattern Analysis and Machine
|
||||
Intelligence, Vol. PAMI-2, No. 1, 67-71.
|
||||
- Gates, G.W. (1972) "The Reduced Nearest Neighbor Rule". IEEE Transactions
|
||||
on Information Theory, May 1972, 431-433.
|
||||
- See also: 1988 MLC Proceedings, 54-64. Cheeseman et al"s AUTOCLASS II
|
||||
conceptual clustering system finds 3 classes in the data.
|
||||
- Many, many more ...
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
.. _kddcup99_dataset:
|
||||
|
||||
Kddcup 99 dataset
|
||||
-----------------
|
||||
|
||||
The KDD Cup '99 dataset was created by processing the tcpdump portions
|
||||
of the 1998 DARPA Intrusion Detection System (IDS) Evaluation dataset,
|
||||
created by MIT Lincoln Lab [2]_. The artificial data (described on the `dataset's
|
||||
homepage <https://kdd.ics.uci.edu/databases/kddcup99/kddcup99.html>`_) was
|
||||
generated using a closed network and hand-injected attacks to produce a
|
||||
large number of different types of attack with normal activity in the
|
||||
background. As the initial goal was to produce a large training set for
|
||||
supervised learning algorithms, there is a large proportion (80.1%) of
|
||||
abnormal data which is unrealistic in real world, and inappropriate for
|
||||
unsupervised anomaly detection which aims at detecting 'abnormal' data, i.e.:
|
||||
|
||||
* qualitatively different from normal data
|
||||
* in large minority among the observations.
|
||||
|
||||
We thus transform the KDD Data set into two different data sets: SA and SF.
|
||||
|
||||
* SA is obtained by simply selecting all the normal data, and a small
|
||||
proportion of abnormal data to gives an anomaly proportion of 1%.
|
||||
|
||||
* SF is obtained as in [3]_
|
||||
by simply picking up the data whose attribute logged_in is positive, thus
|
||||
focusing on the intrusion attack, which gives a proportion of 0.3% of
|
||||
attack.
|
||||
|
||||
* http and smtp are two subsets of SF corresponding with third feature
|
||||
equal to 'http' (resp. to 'smtp').
|
||||
|
||||
General KDD structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 4898431
|
||||
Dimensionality 41
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
SA structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 976158
|
||||
Dimensionality 41
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
SF structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 699691
|
||||
Dimensionality 4
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
http structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 619052
|
||||
Dimensionality 3
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
smtp structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 95373
|
||||
Dimensionality 3
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
:func:`sklearn.datasets.fetch_kddcup99` will load the kddcup99 dataset; it
|
||||
returns a dictionary-like object with the feature matrix in the ``data`` member
|
||||
and the target values in ``target``. The "as_frame" optional argument converts
|
||||
``data`` into a pandas DataFrame and ``target`` into a pandas Series. The
|
||||
dataset will be downloaded from the web if necessary.
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
.. [2] Analysis and Results of the 1999 DARPA Off-Line Intrusion
|
||||
Detection Evaluation, Richard Lippmann, Joshua W. Haines,
|
||||
David J. Fried, Jonathan Korba, Kumar Das.
|
||||
|
||||
.. [3] K. Yamanishi, J.-I. Takeuchi, G. Williams, and P. Milne. Online
|
||||
unsupervised outlier detection using finite mixtures with
|
||||
discounting learning algorithms. In Proceedings of the sixth
|
||||
ACM SIGKDD international conference on Knowledge discovery
|
||||
and data mining, pages 320-324. ACM Press, 2000.
|
||||
.. _kddcup99_dataset:
|
||||
|
||||
Kddcup 99 dataset
|
||||
-----------------
|
||||
|
||||
The KDD Cup '99 dataset was created by processing the tcpdump portions
|
||||
of the 1998 DARPA Intrusion Detection System (IDS) Evaluation dataset,
|
||||
created by MIT Lincoln Lab [2]_. The artificial data (described on the `dataset's
|
||||
homepage <https://kdd.ics.uci.edu/databases/kddcup99/kddcup99.html>`_) was
|
||||
generated using a closed network and hand-injected attacks to produce a
|
||||
large number of different types of attack with normal activity in the
|
||||
background. As the initial goal was to produce a large training set for
|
||||
supervised learning algorithms, there is a large proportion (80.1%) of
|
||||
abnormal data which is unrealistic in real world, and inappropriate for
|
||||
unsupervised anomaly detection which aims at detecting 'abnormal' data, i.e.:
|
||||
|
||||
* qualitatively different from normal data
|
||||
* in large minority among the observations.
|
||||
|
||||
We thus transform the KDD Data set into two different data sets: SA and SF.
|
||||
|
||||
* SA is obtained by simply selecting all the normal data, and a small
|
||||
proportion of abnormal data to gives an anomaly proportion of 1%.
|
||||
|
||||
* SF is obtained as in [3]_
|
||||
by simply picking up the data whose attribute logged_in is positive, thus
|
||||
focusing on the intrusion attack, which gives a proportion of 0.3% of
|
||||
attack.
|
||||
|
||||
* http and smtp are two subsets of SF corresponding with third feature
|
||||
equal to 'http' (resp. to 'smtp').
|
||||
|
||||
General KDD structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 4898431
|
||||
Dimensionality 41
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
SA structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 976158
|
||||
Dimensionality 41
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
SF structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 699691
|
||||
Dimensionality 4
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
http structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 619052
|
||||
Dimensionality 3
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
smtp structure:
|
||||
|
||||
================ ==========================================
|
||||
Samples total 95373
|
||||
Dimensionality 3
|
||||
Features discrete (int) or continuous (float)
|
||||
Targets str, 'normal.' or name of the anomaly type
|
||||
================ ==========================================
|
||||
|
||||
:func:`sklearn.datasets.fetch_kddcup99` will load the kddcup99 dataset; it
|
||||
returns a dictionary-like object with the feature matrix in the ``data`` member
|
||||
and the target values in ``target``. The "as_frame" optional argument converts
|
||||
``data`` into a pandas DataFrame and ``target`` into a pandas Series. The
|
||||
dataset will be downloaded from the web if necessary.
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
.. [2] Analysis and Results of the 1999 DARPA Off-Line Intrusion
|
||||
Detection Evaluation, Richard Lippmann, Joshua W. Haines,
|
||||
David J. Fried, Jonathan Korba, Kumar Das.
|
||||
|
||||
.. [3] K. Yamanishi, J.-I. Takeuchi, G. Williams, and P. Milne. Online
|
||||
unsupervised outlier detection using finite mixtures with
|
||||
discounting learning algorithms. In Proceedings of the sixth
|
||||
ACM SIGKDD international conference on Knowledge discovery
|
||||
and data mining, pages 320-324. ACM Press, 2000.
|
||||
|
||||
@@ -1,124 +1,124 @@
|
||||
.. _labeled_faces_in_the_wild_dataset:
|
||||
|
||||
The Labeled Faces in the Wild face recognition dataset
|
||||
------------------------------------------------------
|
||||
|
||||
This dataset is a collection of JPEG pictures of famous people collected
|
||||
over the internet, and the details are available on the Kaggle website:
|
||||
|
||||
https://www.kaggle.com/datasets/jessicali9530/lfw-dataset
|
||||
|
||||
Each picture is centered on a single face. The typical task is called
|
||||
Face Verification: given a pair of two pictures, a binary classifier
|
||||
must predict whether the two images are from the same person.
|
||||
|
||||
An alternative task, Face Recognition or Face Identification is:
|
||||
given the picture of the face of an unknown person, identify the name
|
||||
of the person by referring to a gallery of previously seen pictures of
|
||||
identified persons.
|
||||
|
||||
Both Face Verification and Face Recognition are tasks that are typically
|
||||
performed on the output of a model trained to perform Face Detection. The
|
||||
most popular model for Face Detection is called Viola-Jones and is
|
||||
implemented in the OpenCV library. The LFW faces were extracted by this
|
||||
face detector from various online websites.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
================= =======================
|
||||
Classes 5749
|
||||
Samples total 13233
|
||||
Dimensionality 5828
|
||||
Features real, between 0 and 255
|
||||
================= =======================
|
||||
|
||||
.. dropdown:: Usage
|
||||
|
||||
``scikit-learn`` provides two loaders that will automatically download,
|
||||
cache, parse the metadata files, decode the jpeg and convert the
|
||||
interesting slices into memmapped numpy arrays. This dataset size is more
|
||||
than 200 MB. The first load typically takes more than a couple of minutes
|
||||
to fully decode the relevant part of the JPEG files into numpy arrays. If
|
||||
the dataset has been loaded once, the following times the loading times
|
||||
less than 200ms by using a memmapped version memoized on the disk in the
|
||||
``~/scikit_learn_data/lfw_home/`` folder using ``joblib``.
|
||||
|
||||
The first loader is used for the Face Identification task: a multi-class
|
||||
classification task (hence supervised learning)::
|
||||
|
||||
>>> from sklearn.datasets import fetch_lfw_people
|
||||
>>> lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
|
||||
|
||||
>>> for name in lfw_people.target_names:
|
||||
... print(name)
|
||||
...
|
||||
Ariel Sharon
|
||||
Colin Powell
|
||||
Donald Rumsfeld
|
||||
George W Bush
|
||||
Gerhard Schroeder
|
||||
Hugo Chavez
|
||||
Tony Blair
|
||||
|
||||
The default slice is a rectangular shape around the face, removing
|
||||
most of the background::
|
||||
|
||||
>>> lfw_people.data.dtype
|
||||
dtype('float32')
|
||||
|
||||
>>> lfw_people.data.shape
|
||||
(1288, 1850)
|
||||
|
||||
>>> lfw_people.images.shape
|
||||
(1288, 50, 37)
|
||||
|
||||
Each of the ``1140`` faces is assigned to a single person id in the ``target``
|
||||
array::
|
||||
|
||||
>>> lfw_people.target.shape
|
||||
(1288,)
|
||||
|
||||
>>> list(lfw_people.target[:10])
|
||||
[5, 6, 3, 1, 0, 1, 3, 4, 3, 0]
|
||||
|
||||
The second loader is typically used for the face verification task: each sample
|
||||
is a pair of two picture belonging or not to the same person::
|
||||
|
||||
>>> from sklearn.datasets import fetch_lfw_pairs
|
||||
>>> lfw_pairs_train = fetch_lfw_pairs(subset='train')
|
||||
|
||||
>>> list(lfw_pairs_train.target_names)
|
||||
['Different persons', 'Same person']
|
||||
|
||||
>>> lfw_pairs_train.pairs.shape
|
||||
(2200, 2, 62, 47)
|
||||
|
||||
>>> lfw_pairs_train.data.shape
|
||||
(2200, 5828)
|
||||
|
||||
>>> lfw_pairs_train.target.shape
|
||||
(2200,)
|
||||
|
||||
Both for the :func:`sklearn.datasets.fetch_lfw_people` and
|
||||
:func:`sklearn.datasets.fetch_lfw_pairs` function it is
|
||||
possible to get an additional dimension with the RGB color channels by
|
||||
passing ``color=True``, in that case the shape will be
|
||||
``(2200, 2, 62, 47, 3)``.
|
||||
|
||||
The :func:`sklearn.datasets.fetch_lfw_pairs` datasets is subdivided into
|
||||
3 subsets: the development ``train`` set, the development ``test`` set and
|
||||
an evaluation ``10_folds`` set meant to compute performance metrics using a
|
||||
10-folds cross validation scheme.
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
* `Labeled Faces in the Wild: A Database for Studying Face Recognition
|
||||
in Unconstrained Environments.
|
||||
<https://people.cs.umass.edu/~elm/papers/lfw.pdf>`_
|
||||
Gary B. Huang, Manu Ramesh, Tamara Berg, and Erik Learned-Miller.
|
||||
University of Massachusetts, Amherst, Technical Report 07-49, October, 2007.
|
||||
|
||||
|
||||
.. rubric:: Examples
|
||||
|
||||
* :ref:`sphx_glr_auto_examples_applications_plot_face_recognition.py`
|
||||
.. _labeled_faces_in_the_wild_dataset:
|
||||
|
||||
The Labeled Faces in the Wild face recognition dataset
|
||||
------------------------------------------------------
|
||||
|
||||
This dataset is a collection of JPEG pictures of famous people collected
|
||||
over the internet, and the details are available on the Kaggle website:
|
||||
|
||||
https://www.kaggle.com/datasets/jessicali9530/lfw-dataset
|
||||
|
||||
Each picture is centered on a single face. The typical task is called
|
||||
Face Verification: given a pair of two pictures, a binary classifier
|
||||
must predict whether the two images are from the same person.
|
||||
|
||||
An alternative task, Face Recognition or Face Identification is:
|
||||
given the picture of the face of an unknown person, identify the name
|
||||
of the person by referring to a gallery of previously seen pictures of
|
||||
identified persons.
|
||||
|
||||
Both Face Verification and Face Recognition are tasks that are typically
|
||||
performed on the output of a model trained to perform Face Detection. The
|
||||
most popular model for Face Detection is called Viola-Jones and is
|
||||
implemented in the OpenCV library. The LFW faces were extracted by this
|
||||
face detector from various online websites.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
================= =======================
|
||||
Classes 5749
|
||||
Samples total 13233
|
||||
Dimensionality 5828
|
||||
Features real, between 0 and 255
|
||||
================= =======================
|
||||
|
||||
.. dropdown:: Usage
|
||||
|
||||
``scikit-learn`` provides two loaders that will automatically download,
|
||||
cache, parse the metadata files, decode the jpeg and convert the
|
||||
interesting slices into memmapped numpy arrays. This dataset size is more
|
||||
than 200 MB. The first load typically takes more than a couple of minutes
|
||||
to fully decode the relevant part of the JPEG files into numpy arrays. If
|
||||
the dataset has been loaded once, the following times the loading times
|
||||
less than 200ms by using a memmapped version memoized on the disk in the
|
||||
``~/scikit_learn_data/lfw_home/`` folder using ``joblib``.
|
||||
|
||||
The first loader is used for the Face Identification task: a multi-class
|
||||
classification task (hence supervised learning)::
|
||||
|
||||
>>> from sklearn.datasets import fetch_lfw_people
|
||||
>>> lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
|
||||
|
||||
>>> for name in lfw_people.target_names:
|
||||
... print(name)
|
||||
...
|
||||
Ariel Sharon
|
||||
Colin Powell
|
||||
Donald Rumsfeld
|
||||
George W Bush
|
||||
Gerhard Schroeder
|
||||
Hugo Chavez
|
||||
Tony Blair
|
||||
|
||||
The default slice is a rectangular shape around the face, removing
|
||||
most of the background::
|
||||
|
||||
>>> lfw_people.data.dtype
|
||||
dtype('float32')
|
||||
|
||||
>>> lfw_people.data.shape
|
||||
(1288, 1850)
|
||||
|
||||
>>> lfw_people.images.shape
|
||||
(1288, 50, 37)
|
||||
|
||||
Each of the ``1140`` faces is assigned to a single person id in the ``target``
|
||||
array::
|
||||
|
||||
>>> lfw_people.target.shape
|
||||
(1288,)
|
||||
|
||||
>>> list(lfw_people.target[:10])
|
||||
[5, 6, 3, 1, 0, 1, 3, 4, 3, 0]
|
||||
|
||||
The second loader is typically used for the face verification task: each sample
|
||||
is a pair of two picture belonging or not to the same person::
|
||||
|
||||
>>> from sklearn.datasets import fetch_lfw_pairs
|
||||
>>> lfw_pairs_train = fetch_lfw_pairs(subset='train')
|
||||
|
||||
>>> list(lfw_pairs_train.target_names)
|
||||
['Different persons', 'Same person']
|
||||
|
||||
>>> lfw_pairs_train.pairs.shape
|
||||
(2200, 2, 62, 47)
|
||||
|
||||
>>> lfw_pairs_train.data.shape
|
||||
(2200, 5828)
|
||||
|
||||
>>> lfw_pairs_train.target.shape
|
||||
(2200,)
|
||||
|
||||
Both for the :func:`sklearn.datasets.fetch_lfw_people` and
|
||||
:func:`sklearn.datasets.fetch_lfw_pairs` function it is
|
||||
possible to get an additional dimension with the RGB color channels by
|
||||
passing ``color=True``, in that case the shape will be
|
||||
``(2200, 2, 62, 47, 3)``.
|
||||
|
||||
The :func:`sklearn.datasets.fetch_lfw_pairs` datasets is subdivided into
|
||||
3 subsets: the development ``train`` set, the development ``test`` set and
|
||||
an evaluation ``10_folds`` set meant to compute performance metrics using a
|
||||
10-folds cross validation scheme.
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
* `Labeled Faces in the Wild: A Database for Studying Face Recognition
|
||||
in Unconstrained Environments.
|
||||
<https://people.cs.umass.edu/~elm/papers/lfw.pdf>`_
|
||||
Gary B. Huang, Manu Ramesh, Tamara Berg, and Erik Learned-Miller.
|
||||
University of Massachusetts, Amherst, Technical Report 07-49, October, 2007.
|
||||
|
||||
|
||||
.. rubric:: Examples
|
||||
|
||||
* :ref:`sphx_glr_auto_examples_applications_plot_face_recognition.py`
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
.. _linnerrud_dataset:
|
||||
|
||||
Linnerrud dataset
|
||||
-----------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 20
|
||||
:Number of Attributes: 3
|
||||
:Missing Attribute Values: None
|
||||
|
||||
The Linnerud dataset is a multi-output regression dataset. It consists of three
|
||||
exercise (data) and three physiological (target) variables collected from
|
||||
twenty middle-aged men in a fitness club:
|
||||
|
||||
- *physiological* - CSV containing 20 observations on 3 physiological variables:
|
||||
Weight, Waist and Pulse.
|
||||
- *exercise* - CSV containing 20 observations on 3 exercise variables:
|
||||
Chins, Situps and Jumps.
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
* Tenenhaus, M. (1998). La regression PLS: theorie et pratique. Paris:
|
||||
Editions Technic.
|
||||
.. _linnerrud_dataset:
|
||||
|
||||
Linnerrud dataset
|
||||
-----------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 20
|
||||
:Number of Attributes: 3
|
||||
:Missing Attribute Values: None
|
||||
|
||||
The Linnerud dataset is a multi-output regression dataset. It consists of three
|
||||
exercise (data) and three physiological (target) variables collected from
|
||||
twenty middle-aged men in a fitness club:
|
||||
|
||||
- *physiological* - CSV containing 20 observations on 3 physiological variables:
|
||||
Weight, Waist and Pulse.
|
||||
- *exercise* - CSV containing 20 observations on 3 exercise variables:
|
||||
Chins, Situps and Jumps.
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
* Tenenhaus, M. (1998). La regression PLS: theorie et pratique. Paris:
|
||||
Editions Technic.
|
||||
|
||||
+44
-44
@@ -1,44 +1,44 @@
|
||||
.. _olivetti_faces_dataset:
|
||||
|
||||
The Olivetti faces dataset
|
||||
--------------------------
|
||||
|
||||
`This dataset contains a set of face images`_ taken between April 1992 and
|
||||
April 1994 at AT&T Laboratories Cambridge. The
|
||||
:func:`sklearn.datasets.fetch_olivetti_faces` function is the data
|
||||
fetching / caching function that downloads the data
|
||||
archive from AT&T.
|
||||
|
||||
.. _This dataset contains a set of face images: https://cam-orl.co.uk/facedatabase.html
|
||||
|
||||
As described on the original website:
|
||||
|
||||
There are ten different images of each of 40 distinct subjects. For some
|
||||
subjects, the images were taken at different times, varying the lighting,
|
||||
facial expressions (open / closed eyes, smiling / not smiling) and facial
|
||||
details (glasses / no glasses). All the images were taken against a dark
|
||||
homogeneous background with the subjects in an upright, frontal position
|
||||
(with tolerance for some side movement).
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
================= =====================
|
||||
Classes 40
|
||||
Samples total 400
|
||||
Dimensionality 4096
|
||||
Features real, between 0 and 1
|
||||
================= =====================
|
||||
|
||||
The image is quantized to 256 grey levels and stored as unsigned 8-bit
|
||||
integers; the loader will convert these to floating point values on the
|
||||
interval [0, 1], which are easier to work with for many algorithms.
|
||||
|
||||
The "target" for this database is an integer from 0 to 39 indicating the
|
||||
identity of the person pictured; however, with only 10 examples per class, this
|
||||
relatively small dataset is more interesting from an unsupervised or
|
||||
semi-supervised perspective.
|
||||
|
||||
The original dataset consisted of 92 x 112, while the version available here
|
||||
consists of 64x64 images.
|
||||
|
||||
When using these images, please give credit to AT&T Laboratories Cambridge.
|
||||
.. _olivetti_faces_dataset:
|
||||
|
||||
The Olivetti faces dataset
|
||||
--------------------------
|
||||
|
||||
`This dataset contains a set of face images`_ taken between April 1992 and
|
||||
April 1994 at AT&T Laboratories Cambridge. The
|
||||
:func:`sklearn.datasets.fetch_olivetti_faces` function is the data
|
||||
fetching / caching function that downloads the data
|
||||
archive from AT&T.
|
||||
|
||||
.. _This dataset contains a set of face images: https://cam-orl.co.uk/facedatabase.html
|
||||
|
||||
As described on the original website:
|
||||
|
||||
There are ten different images of each of 40 distinct subjects. For some
|
||||
subjects, the images were taken at different times, varying the lighting,
|
||||
facial expressions (open / closed eyes, smiling / not smiling) and facial
|
||||
details (glasses / no glasses). All the images were taken against a dark
|
||||
homogeneous background with the subjects in an upright, frontal position
|
||||
(with tolerance for some side movement).
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
================= =====================
|
||||
Classes 40
|
||||
Samples total 400
|
||||
Dimensionality 4096
|
||||
Features real, between 0 and 1
|
||||
================= =====================
|
||||
|
||||
The image is quantized to 256 grey levels and stored as unsigned 8-bit
|
||||
integers; the loader will convert these to floating point values on the
|
||||
interval [0, 1], which are easier to work with for many algorithms.
|
||||
|
||||
The "target" for this database is an integer from 0 to 39 indicating the
|
||||
identity of the person pictured; however, with only 10 examples per class, this
|
||||
relatively small dataset is more interesting from an unsupervised or
|
||||
semi-supervised perspective.
|
||||
|
||||
The original dataset consisted of 92 x 112, while the version available here
|
||||
consists of 64x64 images.
|
||||
|
||||
When using these images, please give credit to AT&T Laboratories Cambridge.
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
.. _rcv1_dataset:
|
||||
|
||||
RCV1 dataset
|
||||
------------
|
||||
|
||||
Reuters Corpus Volume I (RCV1) is an archive of over 800,000 manually
|
||||
categorized newswire stories made available by Reuters, Ltd. for research
|
||||
purposes. The dataset is extensively described in [1]_.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
============== =====================
|
||||
Classes 103
|
||||
Samples total 804414
|
||||
Dimensionality 47236
|
||||
Features real, between 0 and 1
|
||||
============== =====================
|
||||
|
||||
:func:`sklearn.datasets.fetch_rcv1` will load the following
|
||||
version: RCV1-v2, vectors, full sets, topics multilabels::
|
||||
|
||||
>>> from sklearn.datasets import fetch_rcv1
|
||||
>>> rcv1 = fetch_rcv1()
|
||||
|
||||
It returns a dictionary-like object, with the following attributes:
|
||||
|
||||
``data``:
|
||||
The feature matrix is a scipy CSR sparse matrix, with 804414 samples and
|
||||
47236 features. Non-zero values contains cosine-normalized, log TF-IDF vectors.
|
||||
A nearly chronological split is proposed in [1]_: The first 23149 samples are
|
||||
the training set. The last 781265 samples are the testing set. This follows
|
||||
the official LYRL2004 chronological split. The array has 0.16% of non zero
|
||||
values::
|
||||
|
||||
>>> rcv1.data.shape
|
||||
(804414, 47236)
|
||||
|
||||
``target``:
|
||||
The target values are stored in a scipy CSR sparse matrix, with 804414 samples
|
||||
and 103 categories. Each sample has a value of 1 in its categories, and 0 in
|
||||
others. The array has 3.15% of non zero values::
|
||||
|
||||
>>> rcv1.target.shape
|
||||
(804414, 103)
|
||||
|
||||
``sample_id``:
|
||||
Each sample can be identified by its ID, ranging (with gaps) from 2286
|
||||
to 810596::
|
||||
|
||||
>>> rcv1.sample_id[:3]
|
||||
array([2286, 2287, 2288], dtype=uint32)
|
||||
|
||||
``target_names``:
|
||||
The target values are the topics of each sample. Each sample belongs to at
|
||||
least one topic, and to up to 17 topics. There are 103 topics, each
|
||||
represented by a string. Their corpus frequencies span five orders of
|
||||
magnitude, from 5 occurrences for 'GMIL', to 381327 for 'CCAT'::
|
||||
|
||||
>>> rcv1.target_names[:3].tolist() # doctest: +SKIP
|
||||
['E11', 'ECAT', 'M11']
|
||||
|
||||
The dataset will be downloaded from the `rcv1 homepage`_ if necessary.
|
||||
The compressed size is about 656 MB.
|
||||
|
||||
.. _rcv1 homepage: http://jmlr.csail.mit.edu/papers/volume5/lewis04a/
|
||||
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
.. [1] Lewis, D. D., Yang, Y., Rose, T. G., & Li, F. (2004).
|
||||
RCV1: A new benchmark collection for text categorization research.
|
||||
The Journal of Machine Learning Research, 5, 361-397.
|
||||
.. _rcv1_dataset:
|
||||
|
||||
RCV1 dataset
|
||||
------------
|
||||
|
||||
Reuters Corpus Volume I (RCV1) is an archive of over 800,000 manually
|
||||
categorized newswire stories made available by Reuters, Ltd. for research
|
||||
purposes. The dataset is extensively described in [1]_.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
============== =====================
|
||||
Classes 103
|
||||
Samples total 804414
|
||||
Dimensionality 47236
|
||||
Features real, between 0 and 1
|
||||
============== =====================
|
||||
|
||||
:func:`sklearn.datasets.fetch_rcv1` will load the following
|
||||
version: RCV1-v2, vectors, full sets, topics multilabels::
|
||||
|
||||
>>> from sklearn.datasets import fetch_rcv1
|
||||
>>> rcv1 = fetch_rcv1()
|
||||
|
||||
It returns a dictionary-like object, with the following attributes:
|
||||
|
||||
``data``:
|
||||
The feature matrix is a scipy CSR sparse matrix, with 804414 samples and
|
||||
47236 features. Non-zero values contains cosine-normalized, log TF-IDF vectors.
|
||||
A nearly chronological split is proposed in [1]_: The first 23149 samples are
|
||||
the training set. The last 781265 samples are the testing set. This follows
|
||||
the official LYRL2004 chronological split. The array has 0.16% of non zero
|
||||
values::
|
||||
|
||||
>>> rcv1.data.shape
|
||||
(804414, 47236)
|
||||
|
||||
``target``:
|
||||
The target values are stored in a scipy CSR sparse matrix, with 804414 samples
|
||||
and 103 categories. Each sample has a value of 1 in its categories, and 0 in
|
||||
others. The array has 3.15% of non zero values::
|
||||
|
||||
>>> rcv1.target.shape
|
||||
(804414, 103)
|
||||
|
||||
``sample_id``:
|
||||
Each sample can be identified by its ID, ranging (with gaps) from 2286
|
||||
to 810596::
|
||||
|
||||
>>> rcv1.sample_id[:3]
|
||||
array([2286, 2287, 2288], dtype=uint32)
|
||||
|
||||
``target_names``:
|
||||
The target values are the topics of each sample. Each sample belongs to at
|
||||
least one topic, and to up to 17 topics. There are 103 topics, each
|
||||
represented by a string. Their corpus frequencies span five orders of
|
||||
magnitude, from 5 occurrences for 'GMIL', to 381327 for 'CCAT'::
|
||||
|
||||
>>> rcv1.target_names[:3].tolist() # doctest: +SKIP
|
||||
['E11', 'ECAT', 'M11']
|
||||
|
||||
The dataset will be downloaded from the `rcv1 homepage`_ if necessary.
|
||||
The compressed size is about 656 MB.
|
||||
|
||||
.. _rcv1 homepage: http://jmlr.csail.mit.edu/papers/volume5/lewis04a/
|
||||
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
.. [1] Lewis, D. D., Yang, Y., Rose, T. G., & Li, F. (2004).
|
||||
RCV1: A new benchmark collection for text categorization research.
|
||||
The Journal of Machine Learning Research, 5, 361-397.
|
||||
|
||||
+40
-40
@@ -1,40 +1,40 @@
|
||||
.. _species_distribution_dataset:
|
||||
|
||||
Species distribution dataset
|
||||
----------------------------
|
||||
|
||||
This dataset represents the geographic distribution of two species in Central and
|
||||
South America. The two species are:
|
||||
|
||||
- `"Bradypus variegatus" <http://www.iucnredlist.org/details/3038/0>`_ ,
|
||||
the Brown-throated Sloth.
|
||||
|
||||
- `"Microryzomys minutus" <http://www.iucnredlist.org/details/13408/0>`_ ,
|
||||
also known as the Forest Small Rice Rat, a rodent that lives in Peru,
|
||||
Colombia, Ecuador, Peru, and Venezuela.
|
||||
|
||||
The dataset is not a typical dataset since a :class:`~sklearn.datasets.base.Bunch`
|
||||
containing the attributes `data` and `target` is not returned. Instead, we have
|
||||
information allowing to create a "density" map of the different species.
|
||||
|
||||
The grid for the map can be built using the attributes `x_left_lower_corner`,
|
||||
`y_left_lower_corner`, `Nx`, `Ny` and `grid_size`, which respectively correspond
|
||||
to the x and y coordinates of the lower left corner of the grid, the number of
|
||||
points along the x- and y-axis and the size of the step on the grid.
|
||||
|
||||
The density at each location of the grid is contained in the `coverage` attribute.
|
||||
|
||||
Finally, the `train` and `test` attributes contain information regarding the location
|
||||
of a species at a specific location.
|
||||
|
||||
The dataset is provided by Phillips et. al. (2006).
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
* `"Maximum entropy modeling of species geographic distributions"
|
||||
<http://rob.schapire.net/papers/ecolmod.pdf>`_ S. J. Phillips,
|
||||
R. P. Anderson, R. E. Schapire - Ecological Modelling, 190:231-259, 2006.
|
||||
|
||||
.. rubric:: Examples
|
||||
|
||||
* :ref:`sphx_glr_auto_examples_applications_plot_species_distribution_modeling.py`
|
||||
.. _species_distribution_dataset:
|
||||
|
||||
Species distribution dataset
|
||||
----------------------------
|
||||
|
||||
This dataset represents the geographic distribution of two species in Central and
|
||||
South America. The two species are:
|
||||
|
||||
- `"Bradypus variegatus" <http://www.iucnredlist.org/details/3038/0>`_ ,
|
||||
the Brown-throated Sloth.
|
||||
|
||||
- `"Microryzomys minutus" <http://www.iucnredlist.org/details/13408/0>`_ ,
|
||||
also known as the Forest Small Rice Rat, a rodent that lives in Peru,
|
||||
Colombia, Ecuador, Peru, and Venezuela.
|
||||
|
||||
The dataset is not a typical dataset since a :class:`~sklearn.datasets.base.Bunch`
|
||||
containing the attributes `data` and `target` is not returned. Instead, we have
|
||||
information allowing to create a "density" map of the different species.
|
||||
|
||||
The grid for the map can be built using the attributes `x_left_lower_corner`,
|
||||
`y_left_lower_corner`, `Nx`, `Ny` and `grid_size`, which respectively correspond
|
||||
to the x and y coordinates of the lower left corner of the grid, the number of
|
||||
points along the x- and y-axis and the size of the step on the grid.
|
||||
|
||||
The density at each location of the grid is contained in the `coverage` attribute.
|
||||
|
||||
Finally, the `train` and `test` attributes contain information regarding the location
|
||||
of a species at a specific location.
|
||||
|
||||
The dataset is provided by Phillips et. al. (2006).
|
||||
|
||||
.. rubric:: References
|
||||
|
||||
* `"Maximum entropy modeling of species geographic distributions"
|
||||
<http://rob.schapire.net/papers/ecolmod.pdf>`_ S. J. Phillips,
|
||||
R. P. Anderson, R. E. Schapire - Ecological Modelling, 190:231-259, 2006.
|
||||
|
||||
.. rubric:: Examples
|
||||
|
||||
* :ref:`sphx_glr_auto_examples_applications_plot_species_distribution_modeling.py`
|
||||
|
||||
+248
-248
@@ -1,248 +1,248 @@
|
||||
.. _20newsgroups_dataset:
|
||||
|
||||
The 20 newsgroups text dataset
|
||||
------------------------------
|
||||
|
||||
The 20 newsgroups dataset comprises around 18000 newsgroups posts on
|
||||
20 topics split in two subsets: one for training (or development)
|
||||
and the other one for testing (or for performance evaluation). The split
|
||||
between the train and test set is based upon a messages posted before
|
||||
and after a specific date.
|
||||
|
||||
This module contains two loaders. The first one,
|
||||
:func:`sklearn.datasets.fetch_20newsgroups`,
|
||||
returns a list of the raw texts that can be fed to text feature
|
||||
extractors such as :class:`~sklearn.feature_extraction.text.CountVectorizer`
|
||||
with custom parameters so as to extract feature vectors.
|
||||
The second one, :func:`sklearn.datasets.fetch_20newsgroups_vectorized`,
|
||||
returns ready-to-use features, i.e., it is not necessary to use a feature
|
||||
extractor.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
================= ==========
|
||||
Classes 20
|
||||
Samples total 18846
|
||||
Dimensionality 1
|
||||
Features text
|
||||
================= ==========
|
||||
|
||||
.. dropdown:: Usage
|
||||
|
||||
The :func:`sklearn.datasets.fetch_20newsgroups` function is a data
|
||||
fetching / caching functions that downloads the data archive from
|
||||
the original `20 newsgroups website <http://people.csail.mit.edu/jrennie/20Newsgroups/>`__,
|
||||
extracts the archive contents
|
||||
in the ``~/scikit_learn_data/20news_home`` folder and calls the
|
||||
:func:`sklearn.datasets.load_files` on either the training or
|
||||
testing set folder, or both of them::
|
||||
|
||||
>>> from sklearn.datasets import fetch_20newsgroups
|
||||
>>> newsgroups_train = fetch_20newsgroups(subset='train')
|
||||
|
||||
>>> from pprint import pprint
|
||||
>>> pprint(list(newsgroups_train.target_names))
|
||||
['alt.atheism',
|
||||
'comp.graphics',
|
||||
'comp.os.ms-windows.misc',
|
||||
'comp.sys.ibm.pc.hardware',
|
||||
'comp.sys.mac.hardware',
|
||||
'comp.windows.x',
|
||||
'misc.forsale',
|
||||
'rec.autos',
|
||||
'rec.motorcycles',
|
||||
'rec.sport.baseball',
|
||||
'rec.sport.hockey',
|
||||
'sci.crypt',
|
||||
'sci.electronics',
|
||||
'sci.med',
|
||||
'sci.space',
|
||||
'soc.religion.christian',
|
||||
'talk.politics.guns',
|
||||
'talk.politics.mideast',
|
||||
'talk.politics.misc',
|
||||
'talk.religion.misc']
|
||||
|
||||
The real data lies in the ``filenames`` and ``target`` attributes. The target
|
||||
attribute is the integer index of the category::
|
||||
|
||||
>>> newsgroups_train.filenames.shape
|
||||
(11314,)
|
||||
>>> newsgroups_train.target.shape
|
||||
(11314,)
|
||||
>>> newsgroups_train.target[:10]
|
||||
array([ 7, 4, 4, 1, 14, 16, 13, 3, 2, 4])
|
||||
|
||||
It is possible to load only a sub-selection of the categories by passing the
|
||||
list of the categories to load to the
|
||||
:func:`sklearn.datasets.fetch_20newsgroups` function::
|
||||
|
||||
>>> cats = ['alt.atheism', 'sci.space']
|
||||
>>> newsgroups_train = fetch_20newsgroups(subset='train', categories=cats)
|
||||
|
||||
>>> list(newsgroups_train.target_names)
|
||||
['alt.atheism', 'sci.space']
|
||||
>>> newsgroups_train.filenames.shape
|
||||
(1073,)
|
||||
>>> newsgroups_train.target.shape
|
||||
(1073,)
|
||||
>>> newsgroups_train.target[:10]
|
||||
array([0, 1, 1, 1, 0, 1, 1, 0, 0, 0])
|
||||
|
||||
.. dropdown:: Converting text to vectors
|
||||
|
||||
In order to feed predictive or clustering models with the text data,
|
||||
one first need to turn the text into vectors of numerical values suitable
|
||||
for statistical analysis. This can be achieved with the utilities of the
|
||||
``sklearn.feature_extraction.text`` as demonstrated in the following
|
||||
example that extract `TF-IDF <https://en.wikipedia.org/wiki/Tf-idf>`__ vectors
|
||||
of unigram tokens from a subset of 20news::
|
||||
|
||||
>>> from sklearn.feature_extraction.text import TfidfVectorizer
|
||||
>>> categories = ['alt.atheism', 'talk.religion.misc',
|
||||
... 'comp.graphics', 'sci.space']
|
||||
>>> newsgroups_train = fetch_20newsgroups(subset='train',
|
||||
... categories=categories)
|
||||
>>> vectorizer = TfidfVectorizer()
|
||||
>>> vectors = vectorizer.fit_transform(newsgroups_train.data)
|
||||
>>> vectors.shape
|
||||
(2034, 34118)
|
||||
|
||||
The extracted TF-IDF vectors are very sparse, with an average of 159 non-zero
|
||||
components by sample in a more than 30000-dimensional space
|
||||
(less than .5% non-zero features)::
|
||||
|
||||
>>> vectors.nnz / float(vectors.shape[0])
|
||||
159.01327...
|
||||
|
||||
:func:`sklearn.datasets.fetch_20newsgroups_vectorized` is a function which
|
||||
returns ready-to-use token counts features instead of file names.
|
||||
|
||||
.. dropdown:: Filtering text for more realistic training
|
||||
|
||||
It is easy for a classifier to overfit on particular things that appear in the
|
||||
20 Newsgroups data, such as newsgroup headers. Many classifiers achieve very
|
||||
high F-scores, but their results would not generalize to other documents that
|
||||
aren't from this window of time.
|
||||
|
||||
For example, let's look at the results of a multinomial Naive Bayes classifier,
|
||||
which is fast to train and achieves a decent F-score::
|
||||
|
||||
>>> from sklearn.naive_bayes import MultinomialNB
|
||||
>>> from sklearn import metrics
|
||||
>>> newsgroups_test = fetch_20newsgroups(subset='test',
|
||||
... categories=categories)
|
||||
>>> vectors_test = vectorizer.transform(newsgroups_test.data)
|
||||
>>> clf = MultinomialNB(alpha=.01)
|
||||
>>> clf.fit(vectors, newsgroups_train.target)
|
||||
MultinomialNB(alpha=0.01, class_prior=None, fit_prior=True)
|
||||
|
||||
>>> pred = clf.predict(vectors_test)
|
||||
>>> metrics.f1_score(newsgroups_test.target, pred, average='macro')
|
||||
0.88213...
|
||||
|
||||
(The example :ref:`sphx_glr_auto_examples_text_plot_document_classification_20newsgroups.py` shuffles
|
||||
the training and test data, instead of segmenting by time, and in that case
|
||||
multinomial Naive Bayes gets a much higher F-score of 0.88. Are you suspicious
|
||||
yet of what's going on inside this classifier?)
|
||||
|
||||
Let's take a look at what the most informative features are:
|
||||
|
||||
>>> import numpy as np
|
||||
>>> def show_top10(classifier, vectorizer, categories):
|
||||
... feature_names = vectorizer.get_feature_names_out()
|
||||
... for i, category in enumerate(categories):
|
||||
... top10 = np.argsort(classifier.coef_[i])[-10:]
|
||||
... print("%s: %s" % (category, " ".join(feature_names[top10])))
|
||||
...
|
||||
>>> show_top10(clf, vectorizer, newsgroups_train.target_names)
|
||||
alt.atheism: edu it and in you that is of to the
|
||||
comp.graphics: edu in graphics it is for and of to the
|
||||
sci.space: edu it that is in and space to of the
|
||||
talk.religion.misc: not it you in is that and to of the
|
||||
|
||||
|
||||
You can now see many things that these features have overfit to:
|
||||
|
||||
- Almost every group is distinguished by whether headers such as
|
||||
``NNTP-Posting-Host:`` and ``Distribution:`` appear more or less often.
|
||||
- Another significant feature involves whether the sender is affiliated with
|
||||
a university, as indicated either by their headers or their signature.
|
||||
- The word "article" is a significant feature, based on how often people quote
|
||||
previous posts like this: "In article [article ID], [name] <[e-mail address]>
|
||||
wrote:"
|
||||
- Other features match the names and e-mail addresses of particular people who
|
||||
were posting at the time.
|
||||
|
||||
With such an abundance of clues that distinguish newsgroups, the classifiers
|
||||
barely have to identify topics from text at all, and they all perform at the
|
||||
same high level.
|
||||
|
||||
For this reason, the functions that load 20 Newsgroups data provide a
|
||||
parameter called **remove**, telling it what kinds of information to strip out
|
||||
of each file. **remove** should be a tuple containing any subset of
|
||||
``('headers', 'footers', 'quotes')``, telling it to remove headers, signature
|
||||
blocks, and quotation blocks respectively.
|
||||
|
||||
>>> newsgroups_test = fetch_20newsgroups(subset='test',
|
||||
... remove=('headers', 'footers', 'quotes'),
|
||||
... categories=categories)
|
||||
>>> vectors_test = vectorizer.transform(newsgroups_test.data)
|
||||
>>> pred = clf.predict(vectors_test)
|
||||
>>> metrics.f1_score(pred, newsgroups_test.target, average='macro')
|
||||
0.77310...
|
||||
|
||||
This classifier lost over a lot of its F-score, just because we removed
|
||||
metadata that has little to do with topic classification.
|
||||
It loses even more if we also strip this metadata from the training data:
|
||||
|
||||
>>> newsgroups_train = fetch_20newsgroups(subset='train',
|
||||
... remove=('headers', 'footers', 'quotes'),
|
||||
... categories=categories)
|
||||
>>> vectors = vectorizer.fit_transform(newsgroups_train.data)
|
||||
>>> clf = MultinomialNB(alpha=.01)
|
||||
>>> clf.fit(vectors, newsgroups_train.target)
|
||||
MultinomialNB(alpha=0.01, class_prior=None, fit_prior=True)
|
||||
|
||||
>>> vectors_test = vectorizer.transform(newsgroups_test.data)
|
||||
>>> pred = clf.predict(vectors_test)
|
||||
>>> metrics.f1_score(newsgroups_test.target, pred, average='macro')
|
||||
0.76995...
|
||||
|
||||
Some other classifiers cope better with this harder version of the task. Try the
|
||||
:ref:`sphx_glr_auto_examples_model_selection_plot_grid_search_text_feature_extraction.py`
|
||||
example with and without the `remove` option to compare the results.
|
||||
|
||||
.. rubric:: Data Considerations
|
||||
|
||||
The Cleveland Indians is a major league baseball team based in Cleveland,
|
||||
Ohio, USA. In December 2020, it was reported that "After several months of
|
||||
discussion sparked by the death of George Floyd and a national reckoning over
|
||||
race and colonialism, the Cleveland Indians have decided to change their
|
||||
name." Team owner Paul Dolan "did make it clear that the team will not make
|
||||
its informal nickname -- the Tribe -- its new team name." "It's not going to
|
||||
be a half-step away from the Indians," Dolan said."We will not have a Native
|
||||
American-themed name."
|
||||
|
||||
https://www.mlb.com/news/cleveland-indians-team-name-change
|
||||
|
||||
.. rubric:: Recommendation
|
||||
|
||||
- When evaluating text classifiers on the 20 Newsgroups data, you
|
||||
should strip newsgroup-related metadata. In scikit-learn, you can do this
|
||||
by setting ``remove=('headers', 'footers', 'quotes')``. The F-score will be
|
||||
lower because it is more realistic.
|
||||
- This text dataset contains data which may be inappropriate for certain NLP
|
||||
applications. An example is listed in the "Data Considerations" section
|
||||
above. The challenge with using current text datasets in NLP for tasks such
|
||||
as sentence completion, clustering, and other applications is that text
|
||||
that is culturally biased and inflammatory will propagate biases. This
|
||||
should be taken into consideration when using the dataset, reviewing the
|
||||
output, and the bias should be documented.
|
||||
|
||||
.. rubric:: Examples
|
||||
|
||||
* :ref:`sphx_glr_auto_examples_model_selection_plot_grid_search_text_feature_extraction.py`
|
||||
* :ref:`sphx_glr_auto_examples_text_plot_document_classification_20newsgroups.py`
|
||||
* :ref:`sphx_glr_auto_examples_text_plot_hashing_vs_dict_vectorizer.py`
|
||||
* :ref:`sphx_glr_auto_examples_text_plot_document_clustering.py`
|
||||
.. _20newsgroups_dataset:
|
||||
|
||||
The 20 newsgroups text dataset
|
||||
------------------------------
|
||||
|
||||
The 20 newsgroups dataset comprises around 18000 newsgroups posts on
|
||||
20 topics split in two subsets: one for training (or development)
|
||||
and the other one for testing (or for performance evaluation). The split
|
||||
between the train and test set is based upon a messages posted before
|
||||
and after a specific date.
|
||||
|
||||
This module contains two loaders. The first one,
|
||||
:func:`sklearn.datasets.fetch_20newsgroups`,
|
||||
returns a list of the raw texts that can be fed to text feature
|
||||
extractors such as :class:`~sklearn.feature_extraction.text.CountVectorizer`
|
||||
with custom parameters so as to extract feature vectors.
|
||||
The second one, :func:`sklearn.datasets.fetch_20newsgroups_vectorized`,
|
||||
returns ready-to-use features, i.e., it is not necessary to use a feature
|
||||
extractor.
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
================= ==========
|
||||
Classes 20
|
||||
Samples total 18846
|
||||
Dimensionality 1
|
||||
Features text
|
||||
================= ==========
|
||||
|
||||
.. dropdown:: Usage
|
||||
|
||||
The :func:`sklearn.datasets.fetch_20newsgroups` function is a data
|
||||
fetching / caching functions that downloads the data archive from
|
||||
the original `20 newsgroups website <http://people.csail.mit.edu/jrennie/20Newsgroups/>`__,
|
||||
extracts the archive contents
|
||||
in the ``~/scikit_learn_data/20news_home`` folder and calls the
|
||||
:func:`sklearn.datasets.load_files` on either the training or
|
||||
testing set folder, or both of them::
|
||||
|
||||
>>> from sklearn.datasets import fetch_20newsgroups
|
||||
>>> newsgroups_train = fetch_20newsgroups(subset='train')
|
||||
|
||||
>>> from pprint import pprint
|
||||
>>> pprint(list(newsgroups_train.target_names))
|
||||
['alt.atheism',
|
||||
'comp.graphics',
|
||||
'comp.os.ms-windows.misc',
|
||||
'comp.sys.ibm.pc.hardware',
|
||||
'comp.sys.mac.hardware',
|
||||
'comp.windows.x',
|
||||
'misc.forsale',
|
||||
'rec.autos',
|
||||
'rec.motorcycles',
|
||||
'rec.sport.baseball',
|
||||
'rec.sport.hockey',
|
||||
'sci.crypt',
|
||||
'sci.electronics',
|
||||
'sci.med',
|
||||
'sci.space',
|
||||
'soc.religion.christian',
|
||||
'talk.politics.guns',
|
||||
'talk.politics.mideast',
|
||||
'talk.politics.misc',
|
||||
'talk.religion.misc']
|
||||
|
||||
The real data lies in the ``filenames`` and ``target`` attributes. The target
|
||||
attribute is the integer index of the category::
|
||||
|
||||
>>> newsgroups_train.filenames.shape
|
||||
(11314,)
|
||||
>>> newsgroups_train.target.shape
|
||||
(11314,)
|
||||
>>> newsgroups_train.target[:10]
|
||||
array([ 7, 4, 4, 1, 14, 16, 13, 3, 2, 4])
|
||||
|
||||
It is possible to load only a sub-selection of the categories by passing the
|
||||
list of the categories to load to the
|
||||
:func:`sklearn.datasets.fetch_20newsgroups` function::
|
||||
|
||||
>>> cats = ['alt.atheism', 'sci.space']
|
||||
>>> newsgroups_train = fetch_20newsgroups(subset='train', categories=cats)
|
||||
|
||||
>>> list(newsgroups_train.target_names)
|
||||
['alt.atheism', 'sci.space']
|
||||
>>> newsgroups_train.filenames.shape
|
||||
(1073,)
|
||||
>>> newsgroups_train.target.shape
|
||||
(1073,)
|
||||
>>> newsgroups_train.target[:10]
|
||||
array([0, 1, 1, 1, 0, 1, 1, 0, 0, 0])
|
||||
|
||||
.. dropdown:: Converting text to vectors
|
||||
|
||||
In order to feed predictive or clustering models with the text data,
|
||||
one first need to turn the text into vectors of numerical values suitable
|
||||
for statistical analysis. This can be achieved with the utilities of the
|
||||
``sklearn.feature_extraction.text`` as demonstrated in the following
|
||||
example that extract `TF-IDF <https://en.wikipedia.org/wiki/Tf-idf>`__ vectors
|
||||
of unigram tokens from a subset of 20news::
|
||||
|
||||
>>> from sklearn.feature_extraction.text import TfidfVectorizer
|
||||
>>> categories = ['alt.atheism', 'talk.religion.misc',
|
||||
... 'comp.graphics', 'sci.space']
|
||||
>>> newsgroups_train = fetch_20newsgroups(subset='train',
|
||||
... categories=categories)
|
||||
>>> vectorizer = TfidfVectorizer()
|
||||
>>> vectors = vectorizer.fit_transform(newsgroups_train.data)
|
||||
>>> vectors.shape
|
||||
(2034, 34118)
|
||||
|
||||
The extracted TF-IDF vectors are very sparse, with an average of 159 non-zero
|
||||
components by sample in a more than 30000-dimensional space
|
||||
(less than .5% non-zero features)::
|
||||
|
||||
>>> vectors.nnz / float(vectors.shape[0])
|
||||
159.01327...
|
||||
|
||||
:func:`sklearn.datasets.fetch_20newsgroups_vectorized` is a function which
|
||||
returns ready-to-use token counts features instead of file names.
|
||||
|
||||
.. dropdown:: Filtering text for more realistic training
|
||||
|
||||
It is easy for a classifier to overfit on particular things that appear in the
|
||||
20 Newsgroups data, such as newsgroup headers. Many classifiers achieve very
|
||||
high F-scores, but their results would not generalize to other documents that
|
||||
aren't from this window of time.
|
||||
|
||||
For example, let's look at the results of a multinomial Naive Bayes classifier,
|
||||
which is fast to train and achieves a decent F-score::
|
||||
|
||||
>>> from sklearn.naive_bayes import MultinomialNB
|
||||
>>> from sklearn import metrics
|
||||
>>> newsgroups_test = fetch_20newsgroups(subset='test',
|
||||
... categories=categories)
|
||||
>>> vectors_test = vectorizer.transform(newsgroups_test.data)
|
||||
>>> clf = MultinomialNB(alpha=.01)
|
||||
>>> clf.fit(vectors, newsgroups_train.target)
|
||||
MultinomialNB(alpha=0.01, class_prior=None, fit_prior=True)
|
||||
|
||||
>>> pred = clf.predict(vectors_test)
|
||||
>>> metrics.f1_score(newsgroups_test.target, pred, average='macro')
|
||||
0.88213...
|
||||
|
||||
(The example :ref:`sphx_glr_auto_examples_text_plot_document_classification_20newsgroups.py` shuffles
|
||||
the training and test data, instead of segmenting by time, and in that case
|
||||
multinomial Naive Bayes gets a much higher F-score of 0.88. Are you suspicious
|
||||
yet of what's going on inside this classifier?)
|
||||
|
||||
Let's take a look at what the most informative features are:
|
||||
|
||||
>>> import numpy as np
|
||||
>>> def show_top10(classifier, vectorizer, categories):
|
||||
... feature_names = vectorizer.get_feature_names_out()
|
||||
... for i, category in enumerate(categories):
|
||||
... top10 = np.argsort(classifier.coef_[i])[-10:]
|
||||
... print("%s: %s" % (category, " ".join(feature_names[top10])))
|
||||
...
|
||||
>>> show_top10(clf, vectorizer, newsgroups_train.target_names)
|
||||
alt.atheism: edu it and in you that is of to the
|
||||
comp.graphics: edu in graphics it is for and of to the
|
||||
sci.space: edu it that is in and space to of the
|
||||
talk.religion.misc: not it you in is that and to of the
|
||||
|
||||
|
||||
You can now see many things that these features have overfit to:
|
||||
|
||||
- Almost every group is distinguished by whether headers such as
|
||||
``NNTP-Posting-Host:`` and ``Distribution:`` appear more or less often.
|
||||
- Another significant feature involves whether the sender is affiliated with
|
||||
a university, as indicated either by their headers or their signature.
|
||||
- The word "article" is a significant feature, based on how often people quote
|
||||
previous posts like this: "In article [article ID], [name] <[e-mail address]>
|
||||
wrote:"
|
||||
- Other features match the names and e-mail addresses of particular people who
|
||||
were posting at the time.
|
||||
|
||||
With such an abundance of clues that distinguish newsgroups, the classifiers
|
||||
barely have to identify topics from text at all, and they all perform at the
|
||||
same high level.
|
||||
|
||||
For this reason, the functions that load 20 Newsgroups data provide a
|
||||
parameter called **remove**, telling it what kinds of information to strip out
|
||||
of each file. **remove** should be a tuple containing any subset of
|
||||
``('headers', 'footers', 'quotes')``, telling it to remove headers, signature
|
||||
blocks, and quotation blocks respectively.
|
||||
|
||||
>>> newsgroups_test = fetch_20newsgroups(subset='test',
|
||||
... remove=('headers', 'footers', 'quotes'),
|
||||
... categories=categories)
|
||||
>>> vectors_test = vectorizer.transform(newsgroups_test.data)
|
||||
>>> pred = clf.predict(vectors_test)
|
||||
>>> metrics.f1_score(pred, newsgroups_test.target, average='macro')
|
||||
0.77310...
|
||||
|
||||
This classifier lost over a lot of its F-score, just because we removed
|
||||
metadata that has little to do with topic classification.
|
||||
It loses even more if we also strip this metadata from the training data:
|
||||
|
||||
>>> newsgroups_train = fetch_20newsgroups(subset='train',
|
||||
... remove=('headers', 'footers', 'quotes'),
|
||||
... categories=categories)
|
||||
>>> vectors = vectorizer.fit_transform(newsgroups_train.data)
|
||||
>>> clf = MultinomialNB(alpha=.01)
|
||||
>>> clf.fit(vectors, newsgroups_train.target)
|
||||
MultinomialNB(alpha=0.01, class_prior=None, fit_prior=True)
|
||||
|
||||
>>> vectors_test = vectorizer.transform(newsgroups_test.data)
|
||||
>>> pred = clf.predict(vectors_test)
|
||||
>>> metrics.f1_score(newsgroups_test.target, pred, average='macro')
|
||||
0.76995...
|
||||
|
||||
Some other classifiers cope better with this harder version of the task. Try the
|
||||
:ref:`sphx_glr_auto_examples_model_selection_plot_grid_search_text_feature_extraction.py`
|
||||
example with and without the `remove` option to compare the results.
|
||||
|
||||
.. rubric:: Data Considerations
|
||||
|
||||
The Cleveland Indians is a major league baseball team based in Cleveland,
|
||||
Ohio, USA. In December 2020, it was reported that "After several months of
|
||||
discussion sparked by the death of George Floyd and a national reckoning over
|
||||
race and colonialism, the Cleveland Indians have decided to change their
|
||||
name." Team owner Paul Dolan "did make it clear that the team will not make
|
||||
its informal nickname -- the Tribe -- its new team name." "It's not going to
|
||||
be a half-step away from the Indians," Dolan said."We will not have a Native
|
||||
American-themed name."
|
||||
|
||||
https://www.mlb.com/news/cleveland-indians-team-name-change
|
||||
|
||||
.. rubric:: Recommendation
|
||||
|
||||
- When evaluating text classifiers on the 20 Newsgroups data, you
|
||||
should strip newsgroup-related metadata. In scikit-learn, you can do this
|
||||
by setting ``remove=('headers', 'footers', 'quotes')``. The F-score will be
|
||||
lower because it is more realistic.
|
||||
- This text dataset contains data which may be inappropriate for certain NLP
|
||||
applications. An example is listed in the "Data Considerations" section
|
||||
above. The challenge with using current text datasets in NLP for tasks such
|
||||
as sentence completion, clustering, and other applications is that text
|
||||
that is culturally biased and inflammatory will propagate biases. This
|
||||
should be taken into consideration when using the dataset, reviewing the
|
||||
output, and the bias should be documented.
|
||||
|
||||
.. rubric:: Examples
|
||||
|
||||
* :ref:`sphx_glr_auto_examples_model_selection_plot_grid_search_text_feature_extraction.py`
|
||||
* :ref:`sphx_glr_auto_examples_text_plot_document_classification_20newsgroups.py`
|
||||
* :ref:`sphx_glr_auto_examples_text_plot_hashing_vs_dict_vectorizer.py`
|
||||
* :ref:`sphx_glr_auto_examples_text_plot_document_clustering.py`
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
.. _wine_dataset:
|
||||
|
||||
Wine recognition dataset
|
||||
------------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 178
|
||||
:Number of Attributes: 13 numeric, predictive attributes and the class
|
||||
:Attribute Information:
|
||||
- Alcohol
|
||||
- Malic acid
|
||||
- Ash
|
||||
- Alcalinity of ash
|
||||
- Magnesium
|
||||
- Total phenols
|
||||
- Flavanoids
|
||||
- Nonflavanoid phenols
|
||||
- Proanthocyanins
|
||||
- Color intensity
|
||||
- Hue
|
||||
- OD280/OD315 of diluted wines
|
||||
- Proline
|
||||
- class:
|
||||
- class_0
|
||||
- class_1
|
||||
- class_2
|
||||
|
||||
:Summary Statistics:
|
||||
|
||||
============================= ==== ===== ======= =====
|
||||
Min Max Mean SD
|
||||
============================= ==== ===== ======= =====
|
||||
Alcohol: 11.0 14.8 13.0 0.8
|
||||
Malic Acid: 0.74 5.80 2.34 1.12
|
||||
Ash: 1.36 3.23 2.36 0.27
|
||||
Alcalinity of Ash: 10.6 30.0 19.5 3.3
|
||||
Magnesium: 70.0 162.0 99.7 14.3
|
||||
Total Phenols: 0.98 3.88 2.29 0.63
|
||||
Flavanoids: 0.34 5.08 2.03 1.00
|
||||
Nonflavanoid Phenols: 0.13 0.66 0.36 0.12
|
||||
Proanthocyanins: 0.41 3.58 1.59 0.57
|
||||
Colour Intensity: 1.3 13.0 5.1 2.3
|
||||
Hue: 0.48 1.71 0.96 0.23
|
||||
OD280/OD315 of diluted wines: 1.27 4.00 2.61 0.71
|
||||
Proline: 278 1680 746 315
|
||||
============================= ==== ===== ======= =====
|
||||
|
||||
:Missing Attribute Values: None
|
||||
:Class Distribution: class_0 (59), class_1 (71), class_2 (48)
|
||||
:Creator: R.A. Fisher
|
||||
:Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)
|
||||
:Date: July, 1988
|
||||
|
||||
This is a copy of UCI ML Wine recognition datasets.
|
||||
https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data
|
||||
|
||||
The data is the results of a chemical analysis of wines grown in the same
|
||||
region in Italy by three different cultivators. There are thirteen different
|
||||
measurements taken for different constituents found in the three types of
|
||||
wine.
|
||||
|
||||
Original Owners:
|
||||
|
||||
Forina, M. et al, PARVUS -
|
||||
An Extendible Package for Data Exploration, Classification and Correlation.
|
||||
Institute of Pharmaceutical and Food Analysis and Technologies,
|
||||
Via Brigata Salerno, 16147 Genoa, Italy.
|
||||
|
||||
Citation:
|
||||
|
||||
Lichman, M. (2013). UCI Machine Learning Repository
|
||||
[https://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
|
||||
School of Information and Computer Science.
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
(1) S. Aeberhard, D. Coomans and O. de Vel,
|
||||
Comparison of Classifiers in High Dimensional Settings,
|
||||
Tech. Rep. no. 92-02, (1992), Dept. of Computer Science and Dept. of
|
||||
Mathematics and Statistics, James Cook University of North Queensland.
|
||||
(Also submitted to Technometrics).
|
||||
|
||||
The data was used with many others for comparing various
|
||||
classifiers. The classes are separable, though only RDA
|
||||
has achieved 100% correct classification.
|
||||
(RDA : 100%, QDA 99.4%, LDA 98.9%, 1NN 96.1% (z-transformed data))
|
||||
(All results using the leave-one-out technique)
|
||||
|
||||
(2) S. Aeberhard, D. Coomans and O. de Vel,
|
||||
"THE CLASSIFICATION PERFORMANCE OF RDA"
|
||||
Tech. Rep. no. 92-01, (1992), Dept. of Computer Science and Dept. of
|
||||
Mathematics and Statistics, James Cook University of North Queensland.
|
||||
(Also submitted to Journal of Chemometrics).
|
||||
.. _wine_dataset:
|
||||
|
||||
Wine recognition dataset
|
||||
------------------------
|
||||
|
||||
**Data Set Characteristics:**
|
||||
|
||||
:Number of Instances: 178
|
||||
:Number of Attributes: 13 numeric, predictive attributes and the class
|
||||
:Attribute Information:
|
||||
- Alcohol
|
||||
- Malic acid
|
||||
- Ash
|
||||
- Alcalinity of ash
|
||||
- Magnesium
|
||||
- Total phenols
|
||||
- Flavanoids
|
||||
- Nonflavanoid phenols
|
||||
- Proanthocyanins
|
||||
- Color intensity
|
||||
- Hue
|
||||
- OD280/OD315 of diluted wines
|
||||
- Proline
|
||||
- class:
|
||||
- class_0
|
||||
- class_1
|
||||
- class_2
|
||||
|
||||
:Summary Statistics:
|
||||
|
||||
============================= ==== ===== ======= =====
|
||||
Min Max Mean SD
|
||||
============================= ==== ===== ======= =====
|
||||
Alcohol: 11.0 14.8 13.0 0.8
|
||||
Malic Acid: 0.74 5.80 2.34 1.12
|
||||
Ash: 1.36 3.23 2.36 0.27
|
||||
Alcalinity of Ash: 10.6 30.0 19.5 3.3
|
||||
Magnesium: 70.0 162.0 99.7 14.3
|
||||
Total Phenols: 0.98 3.88 2.29 0.63
|
||||
Flavanoids: 0.34 5.08 2.03 1.00
|
||||
Nonflavanoid Phenols: 0.13 0.66 0.36 0.12
|
||||
Proanthocyanins: 0.41 3.58 1.59 0.57
|
||||
Colour Intensity: 1.3 13.0 5.1 2.3
|
||||
Hue: 0.48 1.71 0.96 0.23
|
||||
OD280/OD315 of diluted wines: 1.27 4.00 2.61 0.71
|
||||
Proline: 278 1680 746 315
|
||||
============================= ==== ===== ======= =====
|
||||
|
||||
:Missing Attribute Values: None
|
||||
:Class Distribution: class_0 (59), class_1 (71), class_2 (48)
|
||||
:Creator: R.A. Fisher
|
||||
:Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)
|
||||
:Date: July, 1988
|
||||
|
||||
This is a copy of UCI ML Wine recognition datasets.
|
||||
https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data
|
||||
|
||||
The data is the results of a chemical analysis of wines grown in the same
|
||||
region in Italy by three different cultivators. There are thirteen different
|
||||
measurements taken for different constituents found in the three types of
|
||||
wine.
|
||||
|
||||
Original Owners:
|
||||
|
||||
Forina, M. et al, PARVUS -
|
||||
An Extendible Package for Data Exploration, Classification and Correlation.
|
||||
Institute of Pharmaceutical and Food Analysis and Technologies,
|
||||
Via Brigata Salerno, 16147 Genoa, Italy.
|
||||
|
||||
Citation:
|
||||
|
||||
Lichman, M. (2013). UCI Machine Learning Repository
|
||||
[https://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
|
||||
School of Information and Computer Science.
|
||||
|
||||
.. dropdown:: References
|
||||
|
||||
(1) S. Aeberhard, D. Coomans and O. de Vel,
|
||||
Comparison of Classifiers in High Dimensional Settings,
|
||||
Tech. Rep. no. 92-02, (1992), Dept. of Computer Science and Dept. of
|
||||
Mathematics and Statistics, James Cook University of North Queensland.
|
||||
(Also submitted to Technometrics).
|
||||
|
||||
The data was used with many others for comparing various
|
||||
classifiers. The classes are separable, though only RDA
|
||||
has achieved 100% correct classification.
|
||||
(RDA : 100%, QDA 99.4%, LDA 98.9%, 1NN 96.1% (z-transformed data))
|
||||
(All results using the leave-one-out technique)
|
||||
|
||||
(2) S. Aeberhard, D. Coomans and O. de Vel,
|
||||
"THE CLASSIFICATION PERFORMANCE OF RDA"
|
||||
Tech. Rep. no. 92-01, (1992), Dept. of Computer Science and Dept. of
|
||||
Mathematics and Statistics, James Cook University of North Queensland.
|
||||
(Also submitted to Journal of Chemometrics).
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
Image: china.jpg
|
||||
Released under a creative commons license. [1]
|
||||
Attribution: Some rights reserved by danielbuechele [2]
|
||||
Retrieved 21st August, 2011 from [3] by Robert Layton
|
||||
|
||||
[1] https://creativecommons.org/licenses/by/2.0/
|
||||
[2] https://www.flickr.com/photos/danielbuechele/
|
||||
[3] https://www.flickr.com/photos/danielbuechele/6061409035/sizes/z/in/photostream/
|
||||
|
||||
|
||||
Image: flower.jpg
|
||||
Released under a creative commons license. [1]
|
||||
Attribution: Some rights reserved by danielbuechele [2]
|
||||
Retrieved 21st August, 2011 from [3] by Robert Layton
|
||||
|
||||
[1] https://creativecommons.org/licenses/by/2.0/
|
||||
[2] https://www.flickr.com/photos/vultilion/
|
||||
[3] https://www.flickr.com/photos/vultilion/6056698931/sizes/z/in/photostream/
|
||||
Image: china.jpg
|
||||
Released under a creative commons license. [1]
|
||||
Attribution: Some rights reserved by danielbuechele [2]
|
||||
Retrieved 21st August, 2011 from [3] by Robert Layton
|
||||
|
||||
[1] https://creativecommons.org/licenses/by/2.0/
|
||||
[2] https://www.flickr.com/photos/danielbuechele/
|
||||
[3] https://www.flickr.com/photos/danielbuechele/6061409035/sizes/z/in/photostream/
|
||||
|
||||
|
||||
Image: flower.jpg
|
||||
Released under a creative commons license. [1]
|
||||
Attribution: Some rights reserved by danielbuechele [2]
|
||||
Retrieved 21st August, 2011 from [3] by Robert Layton
|
||||
|
||||
[1] https://creativecommons.org/licenses/by/2.0/
|
||||
[2] https://www.flickr.com/photos/vultilion/
|
||||
[3] https://www.flickr.com/photos/vultilion/6056698931/sizes/z/in/photostream/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
py.extension_module(
|
||||
'_svmlight_format_fast',
|
||||
cython_gen.process('_svmlight_format_fast.pyx'),
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/datasets',
|
||||
install: true
|
||||
)
|
||||
py.extension_module(
|
||||
'_svmlight_format_fast',
|
||||
cython_gen.process('_svmlight_format_fast.pyx'),
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/datasets',
|
||||
install: true
|
||||
)
|
||||
|
||||
+9
-9
@@ -1,9 +1,9 @@
|
||||
# comment
|
||||
# note: the next line contains a tab
|
||||
1.0 3:2.5 11:-5.2 16:1.5 # and an inline comment
|
||||
2.0 6:1.0 13:-3
|
||||
# another comment
|
||||
3.0 21:27
|
||||
4.0 2:1.234567890123456e10 # double precision value
|
||||
1.0 # empty line, all zeros
|
||||
2.0 3:0 # explicit zeros
|
||||
# comment
|
||||
# note: the next line contains a tab
|
||||
1.0 3:2.5 11:-5.2 16:1.5 # and an inline comment
|
||||
2.0 6:1.0 13:-3
|
||||
# another comment
|
||||
3.0 21:27
|
||||
4.0 2:1.234567890123456e10 # double precision value
|
||||
1.0 # empty line, all zeros
|
||||
2.0 3:0 # explicit zeros
|
||||
|
||||
+3
-3
@@ -1,3 +1,3 @@
|
||||
python 2:2.5 10:-5.2 15:1.5
|
||||
2.0 5:1.0 12:-3
|
||||
3.0 20:27
|
||||
python 2:2.5 10:-5.2 15:1.5
|
||||
2.0 5:1.0 12:-3
|
||||
3.0 20:27
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
-1 5:2.5 2:-5.2 15:1.5
|
||||
-1 5:2.5 2:-5.2 15:1.5
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
# multilabel dataset in SVMlight format
|
||||
1,0 2:2.5 10:-5.2 15:1.5
|
||||
2 5:1.0 12:-3
|
||||
2:3.5 11:26
|
||||
1,2 20:27
|
||||
# multilabel dataset in SVMlight format
|
||||
1,0 2:2.5 10:-5.2 15:1.5
|
||||
2 5:1.0 12:-3
|
||||
2:3.5 11:26
|
||||
1,2 20:27
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from cython cimport floating
|
||||
from libc.math cimport fabs
|
||||
|
||||
|
||||
def _update_cdnmf_fast(floating[:, ::1] W, floating[:, :] HHt,
|
||||
floating[:, :] XHt, Py_ssize_t[::1] permutation):
|
||||
cdef:
|
||||
floating violation = 0
|
||||
Py_ssize_t n_components = W.shape[1]
|
||||
Py_ssize_t n_samples = W.shape[0] # n_features for H update
|
||||
floating grad, pg, hess
|
||||
Py_ssize_t i, r, s, t
|
||||
|
||||
with nogil:
|
||||
for s in range(n_components):
|
||||
t = permutation[s]
|
||||
|
||||
for i in range(n_samples):
|
||||
# gradient = GW[t, i] where GW = np.dot(W, HHt) - XHt
|
||||
grad = -XHt[i, t]
|
||||
|
||||
for r in range(n_components):
|
||||
grad += HHt[t, r] * W[i, r]
|
||||
|
||||
# projected gradient
|
||||
pg = min(0., grad) if W[i, t] == 0 else grad
|
||||
violation += fabs(pg)
|
||||
|
||||
# Hessian
|
||||
hess = HHt[t, t]
|
||||
|
||||
if hess != 0:
|
||||
W[i, t] = max(W[i, t] - grad / hess, 0.)
|
||||
|
||||
return violation
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from cython cimport floating
|
||||
from libc.math cimport fabs
|
||||
|
||||
|
||||
def _update_cdnmf_fast(floating[:, ::1] W, floating[:, :] HHt,
|
||||
floating[:, :] XHt, Py_ssize_t[::1] permutation):
|
||||
cdef:
|
||||
floating violation = 0
|
||||
Py_ssize_t n_components = W.shape[1]
|
||||
Py_ssize_t n_samples = W.shape[0] # n_features for H update
|
||||
floating grad, pg, hess
|
||||
Py_ssize_t i, r, s, t
|
||||
|
||||
with nogil:
|
||||
for s in range(n_components):
|
||||
t = permutation[s]
|
||||
|
||||
for i in range(n_samples):
|
||||
# gradient = GW[t, i] where GW = np.dot(W, HHt) - XHt
|
||||
grad = -XHt[i, t]
|
||||
|
||||
for r in range(n_components):
|
||||
grad += HHt[t, r] * W[i, r]
|
||||
|
||||
# projected gradient
|
||||
pg = min(0., grad) if W[i, t] == 0 else grad
|
||||
violation += fabs(pg)
|
||||
|
||||
# Hessian
|
||||
hess = HHt[t, t]
|
||||
|
||||
if hess != 0:
|
||||
W[i, t] = max(W[i, t] - grad / hess, 0.)
|
||||
|
||||
return violation
|
||||
|
||||
+110
-110
@@ -1,110 +1,110 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
from cython cimport floating
|
||||
from libc.math cimport exp, fabs, log
|
||||
|
||||
from ..utils._typedefs cimport float64_t, intp_t
|
||||
|
||||
|
||||
def mean_change(const floating[:] arr_1, const floating[:] arr_2):
|
||||
"""Calculate the mean difference between two arrays.
|
||||
|
||||
Equivalent to np.abs(arr_1 - arr2).mean().
|
||||
"""
|
||||
|
||||
cdef float64_t total, diff
|
||||
cdef intp_t i, size
|
||||
|
||||
size = arr_1.shape[0]
|
||||
total = 0.0
|
||||
for i in range(size):
|
||||
diff = fabs(arr_1[i] - arr_2[i])
|
||||
total += diff
|
||||
|
||||
return total / size
|
||||
|
||||
|
||||
def _dirichlet_expectation_1d(
|
||||
floating[:] doc_topic,
|
||||
floating doc_topic_prior,
|
||||
floating[:] out
|
||||
):
|
||||
"""Dirichlet expectation for a single sample:
|
||||
exp(E[log(theta)]) for theta ~ Dir(doc_topic)
|
||||
after adding doc_topic_prior to doc_topic, in-place.
|
||||
|
||||
Equivalent to
|
||||
doc_topic += doc_topic_prior
|
||||
out[:] = np.exp(psi(doc_topic) - psi(np.sum(doc_topic)))
|
||||
"""
|
||||
|
||||
cdef floating dt, psi_total, total
|
||||
cdef intp_t i, size
|
||||
|
||||
size = doc_topic.shape[0]
|
||||
|
||||
total = 0.0
|
||||
for i in range(size):
|
||||
dt = doc_topic[i] + doc_topic_prior
|
||||
doc_topic[i] = dt
|
||||
total += dt
|
||||
psi_total = psi(total)
|
||||
|
||||
for i in range(size):
|
||||
out[i] = exp(psi(doc_topic[i]) - psi_total)
|
||||
|
||||
|
||||
def _dirichlet_expectation_2d(const floating[:, :] arr):
|
||||
"""Dirichlet expectation for multiple samples:
|
||||
E[log(theta)] for theta ~ Dir(arr).
|
||||
|
||||
Equivalent to psi(arr) - psi(np.sum(arr, axis=1))[:, np.newaxis].
|
||||
|
||||
Note that unlike _dirichlet_expectation_1d, this function doesn't compute
|
||||
the exp and doesn't add in the prior.
|
||||
"""
|
||||
cdef floating row_total, psi_row_total
|
||||
cdef floating[:, :] d_exp
|
||||
cdef intp_t i, j, n_rows, n_cols
|
||||
|
||||
n_rows = arr.shape[0]
|
||||
n_cols = arr.shape[1]
|
||||
|
||||
d_exp = np.empty_like(arr)
|
||||
for i in range(n_rows):
|
||||
row_total = 0
|
||||
for j in range(n_cols):
|
||||
row_total += arr[i, j]
|
||||
psi_row_total = psi(row_total)
|
||||
|
||||
for j in range(n_cols):
|
||||
d_exp[i, j] = psi(arr[i, j]) - psi_row_total
|
||||
|
||||
return d_exp.base
|
||||
|
||||
|
||||
# Psi function for positive arguments. Optimized for speed, not accuracy.
|
||||
#
|
||||
# After: J. Bernardo (1976). Algorithm AS 103: Psi (Digamma) Function.
|
||||
# https://www.uv.es/~bernardo/1976AppStatist.pdf
|
||||
cdef floating psi(floating x) noexcept nogil:
|
||||
cdef double EULER = 0.577215664901532860606512090082402431
|
||||
if x <= 1e-6:
|
||||
# psi(x) = -EULER - 1/x + O(x)
|
||||
return -EULER - 1. / x
|
||||
|
||||
cdef floating r, result = 0
|
||||
|
||||
# psi(x + 1) = psi(x) + 1/x
|
||||
while x < 6:
|
||||
result -= 1. / x
|
||||
x += 1
|
||||
|
||||
# psi(x) = log(x) - 1/(2x) - 1/(12x**2) + 1/(120x**4) - 1/(252x**6)
|
||||
# + O(1/x**8)
|
||||
r = 1. / x
|
||||
result += log(x) - .5 * r
|
||||
r = r * r
|
||||
result -= r * ((1./12.) - r * ((1./120.) - r * (1./252.)))
|
||||
return result
|
||||
import numpy as np
|
||||
|
||||
|
||||
from cython cimport floating
|
||||
from libc.math cimport exp, fabs, log
|
||||
|
||||
from ..utils._typedefs cimport float64_t, intp_t
|
||||
|
||||
|
||||
def mean_change(const floating[:] arr_1, const floating[:] arr_2):
|
||||
"""Calculate the mean difference between two arrays.
|
||||
|
||||
Equivalent to np.abs(arr_1 - arr2).mean().
|
||||
"""
|
||||
|
||||
cdef float64_t total, diff
|
||||
cdef intp_t i, size
|
||||
|
||||
size = arr_1.shape[0]
|
||||
total = 0.0
|
||||
for i in range(size):
|
||||
diff = fabs(arr_1[i] - arr_2[i])
|
||||
total += diff
|
||||
|
||||
return total / size
|
||||
|
||||
|
||||
def _dirichlet_expectation_1d(
|
||||
floating[:] doc_topic,
|
||||
floating doc_topic_prior,
|
||||
floating[:] out
|
||||
):
|
||||
"""Dirichlet expectation for a single sample:
|
||||
exp(E[log(theta)]) for theta ~ Dir(doc_topic)
|
||||
after adding doc_topic_prior to doc_topic, in-place.
|
||||
|
||||
Equivalent to
|
||||
doc_topic += doc_topic_prior
|
||||
out[:] = np.exp(psi(doc_topic) - psi(np.sum(doc_topic)))
|
||||
"""
|
||||
|
||||
cdef floating dt, psi_total, total
|
||||
cdef intp_t i, size
|
||||
|
||||
size = doc_topic.shape[0]
|
||||
|
||||
total = 0.0
|
||||
for i in range(size):
|
||||
dt = doc_topic[i] + doc_topic_prior
|
||||
doc_topic[i] = dt
|
||||
total += dt
|
||||
psi_total = psi(total)
|
||||
|
||||
for i in range(size):
|
||||
out[i] = exp(psi(doc_topic[i]) - psi_total)
|
||||
|
||||
|
||||
def _dirichlet_expectation_2d(const floating[:, :] arr):
|
||||
"""Dirichlet expectation for multiple samples:
|
||||
E[log(theta)] for theta ~ Dir(arr).
|
||||
|
||||
Equivalent to psi(arr) - psi(np.sum(arr, axis=1))[:, np.newaxis].
|
||||
|
||||
Note that unlike _dirichlet_expectation_1d, this function doesn't compute
|
||||
the exp and doesn't add in the prior.
|
||||
"""
|
||||
cdef floating row_total, psi_row_total
|
||||
cdef floating[:, :] d_exp
|
||||
cdef intp_t i, j, n_rows, n_cols
|
||||
|
||||
n_rows = arr.shape[0]
|
||||
n_cols = arr.shape[1]
|
||||
|
||||
d_exp = np.empty_like(arr)
|
||||
for i in range(n_rows):
|
||||
row_total = 0
|
||||
for j in range(n_cols):
|
||||
row_total += arr[i, j]
|
||||
psi_row_total = psi(row_total)
|
||||
|
||||
for j in range(n_cols):
|
||||
d_exp[i, j] = psi(arr[i, j]) - psi_row_total
|
||||
|
||||
return d_exp.base
|
||||
|
||||
|
||||
# Psi function for positive arguments. Optimized for speed, not accuracy.
|
||||
#
|
||||
# After: J. Bernardo (1976). Algorithm AS 103: Psi (Digamma) Function.
|
||||
# https://www.uv.es/~bernardo/1976AppStatist.pdf
|
||||
cdef floating psi(floating x) noexcept nogil:
|
||||
cdef double EULER = 0.577215664901532860606512090082402431
|
||||
if x <= 1e-6:
|
||||
# psi(x) = -EULER - 1/x + O(x)
|
||||
return -EULER - 1. / x
|
||||
|
||||
cdef floating r, result = 0
|
||||
|
||||
# psi(x + 1) = psi(x) + 1/x
|
||||
while x < 6:
|
||||
result -= 1. / x
|
||||
x += 1
|
||||
|
||||
# psi(x) = log(x) - 1/(2x) - 1/(12x**2) + 1/(120x**4) - 1/(252x**6)
|
||||
# + O(1/x**8)
|
||||
r = 1. / x
|
||||
result += log(x) - .5 * r
|
||||
r = r * r
|
||||
result -= r * ((1./12.) - r * ((1./120.) - r * (1./252.)))
|
||||
return result
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
py.extension_module(
|
||||
'_online_lda_fast',
|
||||
[cython_gen.process('_online_lda_fast.pyx'), utils_cython_tree],
|
||||
subdir: 'sklearn/decomposition',
|
||||
install: true
|
||||
)
|
||||
|
||||
py.extension_module(
|
||||
'_cdnmf_fast',
|
||||
cython_gen.process('_cdnmf_fast.pyx'),
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/decomposition',
|
||||
install: true
|
||||
)
|
||||
py.extension_module(
|
||||
'_online_lda_fast',
|
||||
[cython_gen.process('_online_lda_fast.pyx'), utils_cython_tree],
|
||||
subdir: 'sklearn/decomposition',
|
||||
install: true
|
||||
)
|
||||
|
||||
py.extension_module(
|
||||
'_cdnmf_fast',
|
||||
cython_gen.process('_cdnmf_fast.pyx'),
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/decomposition',
|
||||
install: true
|
||||
)
|
||||
|
||||
+262
-262
@@ -1,262 +1,262 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from libc.stdlib cimport free
|
||||
from libc.string cimport memset
|
||||
|
||||
import numpy as np
|
||||
from scipy.sparse import issparse
|
||||
|
||||
from ..utils._typedefs cimport float32_t, float64_t, intp_t, int32_t, uint8_t
|
||||
# Note: _tree uses cimport numpy, cnp.import_array, so we need to include
|
||||
# numpy headers in the build configuration of this extension
|
||||
from ..tree._tree cimport Node
|
||||
from ..tree._tree cimport Tree
|
||||
from ..tree._utils cimport safe_realloc
|
||||
|
||||
|
||||
# no namespace lookup for numpy dtype and array creation
|
||||
from numpy import zeros as np_zeros
|
||||
|
||||
|
||||
# constant to mark tree leafs
|
||||
cdef intp_t TREE_LEAF = -1
|
||||
|
||||
cdef void _predict_regression_tree_inplace_fast_dense(
|
||||
const float32_t[:, ::1] X,
|
||||
Node* root_node,
|
||||
double *value,
|
||||
double scale,
|
||||
Py_ssize_t k,
|
||||
float64_t[:, :] out
|
||||
) noexcept nogil:
|
||||
"""Predicts output for regression tree and stores it in ``out[i, k]``.
|
||||
|
||||
This function operates directly on the data arrays of the tree
|
||||
data structures. This is 5x faster than the variant above because
|
||||
it allows us to avoid buffer validation.
|
||||
|
||||
The function assumes that the ndarray that wraps ``X`` is
|
||||
c-continuous.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : float32_t 2d memory view
|
||||
The memory view on the data ndarray of the input ``X``.
|
||||
Assumes that the array is c-continuous.
|
||||
root_node : tree Node pointer
|
||||
Pointer to the main node array of the :class:``sklearn.tree.Tree``.
|
||||
value : np.float64_t pointer
|
||||
The pointer to the data array of the ``value`` array attribute
|
||||
of the :class:``sklearn.tree.Tree``.
|
||||
scale : double
|
||||
A constant to scale the predictions.
|
||||
k : int
|
||||
The index of the tree output to be predicted. Must satisfy
|
||||
0 <= ``k`` < ``K``.
|
||||
out : memory view on array of type np.float64_t
|
||||
The data array where the predictions are stored.
|
||||
``out`` is assumed to be a two-dimensional array of
|
||||
shape ``(n_samples, K)``.
|
||||
"""
|
||||
cdef intp_t n_samples = X.shape[0]
|
||||
cdef Py_ssize_t i
|
||||
cdef Node *node
|
||||
for i in range(n_samples):
|
||||
node = root_node
|
||||
# While node not a leaf
|
||||
while node.left_child != TREE_LEAF:
|
||||
if X[i, node.feature] <= node.threshold:
|
||||
node = root_node + node.left_child
|
||||
else:
|
||||
node = root_node + node.right_child
|
||||
out[i, k] += scale * value[node - root_node]
|
||||
|
||||
|
||||
def _predict_regression_tree_stages_sparse(
|
||||
object[:, :] estimators,
|
||||
object X,
|
||||
double scale,
|
||||
float64_t[:, :] out
|
||||
):
|
||||
"""Predicts output for regression tree inplace and adds scaled value to ``out[i, k]``.
|
||||
|
||||
The function assumes that the ndarray that wraps ``X`` is csr_matrix.
|
||||
"""
|
||||
cdef const float32_t[::1] X_data = X.data
|
||||
cdef const int32_t[::1] X_indices = X.indices
|
||||
cdef const int32_t[::1] X_indptr = X.indptr
|
||||
|
||||
cdef intp_t n_samples = X.shape[0]
|
||||
cdef intp_t n_features = X.shape[1]
|
||||
cdef intp_t n_stages = estimators.shape[0]
|
||||
cdef intp_t n_outputs = estimators.shape[1]
|
||||
|
||||
# Indices and temporary variables
|
||||
cdef intp_t sample_i
|
||||
cdef intp_t feature_i
|
||||
cdef intp_t stage_i
|
||||
cdef intp_t output_i
|
||||
cdef Node *root_node = NULL
|
||||
cdef Node *node = NULL
|
||||
cdef double *value = NULL
|
||||
|
||||
cdef Tree tree
|
||||
cdef Node** nodes = NULL
|
||||
cdef double** values = NULL
|
||||
safe_realloc(&nodes, n_stages * n_outputs)
|
||||
safe_realloc(&values, n_stages * n_outputs)
|
||||
for stage_i in range(n_stages):
|
||||
for output_i in range(n_outputs):
|
||||
tree = estimators[stage_i, output_i].tree_
|
||||
nodes[stage_i * n_outputs + output_i] = tree.nodes
|
||||
values[stage_i * n_outputs + output_i] = tree.value
|
||||
|
||||
# Initialize auxiliary data-structure
|
||||
cdef float32_t feature_value = 0.
|
||||
cdef float32_t* X_sample = NULL
|
||||
|
||||
# feature_to_sample as a data structure records the last seen sample
|
||||
# for each feature; functionally, it is an efficient way to identify
|
||||
# which features are nonzero in the present sample.
|
||||
cdef intp_t* feature_to_sample = NULL
|
||||
|
||||
safe_realloc(&X_sample, n_features)
|
||||
safe_realloc(&feature_to_sample, n_features)
|
||||
|
||||
memset(feature_to_sample, -1, n_features * sizeof(intp_t))
|
||||
|
||||
# Cycle through all samples
|
||||
for sample_i in range(n_samples):
|
||||
for feature_i in range(X_indptr[sample_i], X_indptr[sample_i + 1]):
|
||||
feature_to_sample[X_indices[feature_i]] = sample_i
|
||||
X_sample[X_indices[feature_i]] = X_data[feature_i]
|
||||
|
||||
# Cycle through all stages
|
||||
for stage_i in range(n_stages):
|
||||
# Cycle through all trees
|
||||
for output_i in range(n_outputs):
|
||||
root_node = nodes[stage_i * n_outputs + output_i]
|
||||
value = values[stage_i * n_outputs + output_i]
|
||||
node = root_node
|
||||
|
||||
# While node not a leaf
|
||||
while node.left_child != TREE_LEAF:
|
||||
# ... and node.right_child != TREE_LEAF:
|
||||
if feature_to_sample[node.feature] == sample_i:
|
||||
feature_value = X_sample[node.feature]
|
||||
else:
|
||||
feature_value = 0.
|
||||
|
||||
if feature_value <= node.threshold:
|
||||
node = root_node + node.left_child
|
||||
else:
|
||||
node = root_node + node.right_child
|
||||
out[sample_i, output_i] += scale * value[node - root_node]
|
||||
|
||||
# Free auxiliary arrays
|
||||
free(X_sample)
|
||||
free(feature_to_sample)
|
||||
free(nodes)
|
||||
free(values)
|
||||
|
||||
|
||||
def predict_stages(
|
||||
object[:, :] estimators,
|
||||
object X,
|
||||
double scale,
|
||||
float64_t[:, :] out
|
||||
):
|
||||
"""Add predictions of ``estimators`` to ``out``.
|
||||
|
||||
Each estimator is scaled by ``scale`` before its prediction
|
||||
is added to ``out``.
|
||||
"""
|
||||
cdef Py_ssize_t i
|
||||
cdef Py_ssize_t k
|
||||
cdef Py_ssize_t n_estimators = estimators.shape[0]
|
||||
cdef Py_ssize_t K = estimators.shape[1]
|
||||
cdef Tree tree
|
||||
|
||||
if issparse(X):
|
||||
if X.format != 'csr':
|
||||
raise ValueError("When X is a sparse matrix, a CSR format is"
|
||||
" expected, got {!r}".format(type(X)))
|
||||
_predict_regression_tree_stages_sparse(
|
||||
estimators=estimators, X=X, scale=scale, out=out
|
||||
)
|
||||
else:
|
||||
if not isinstance(X, np.ndarray) or np.isfortran(X):
|
||||
raise ValueError(f"X should be C-ordered np.ndarray, got {type(X)}")
|
||||
|
||||
for i in range(n_estimators):
|
||||
for k in range(K):
|
||||
tree = estimators[i, k].tree_
|
||||
|
||||
# avoid buffer validation by casting to ndarray
|
||||
# and get data pointer
|
||||
# need brackets because of casting operator priority
|
||||
_predict_regression_tree_inplace_fast_dense(
|
||||
X=X,
|
||||
root_node=tree.nodes,
|
||||
value=tree.value,
|
||||
scale=scale,
|
||||
k=k,
|
||||
out=out
|
||||
)
|
||||
# out[:, k] += scale * tree.predict(X).ravel()
|
||||
|
||||
|
||||
def predict_stage(
|
||||
object[:, :] estimators,
|
||||
int stage,
|
||||
object X,
|
||||
double scale,
|
||||
float64_t[:, :] out
|
||||
):
|
||||
"""Add predictions of ``estimators[stage]`` to ``out``.
|
||||
|
||||
Each estimator in the stage is scaled by ``scale`` before
|
||||
its prediction is added to ``out``.
|
||||
"""
|
||||
return predict_stages(
|
||||
estimators=estimators[stage:stage + 1], X=X, scale=scale, out=out
|
||||
)
|
||||
|
||||
|
||||
def _random_sample_mask(
|
||||
intp_t n_total_samples,
|
||||
intp_t n_total_in_bag,
|
||||
random_state
|
||||
):
|
||||
"""Create a random sample mask where ``n_total_in_bag`` elements are set.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n_total_samples : int
|
||||
The length of the resulting mask.
|
||||
|
||||
n_total_in_bag : int
|
||||
The number of elements in the sample mask which are set to 1.
|
||||
|
||||
random_state : RandomState
|
||||
A numpy ``RandomState`` object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
sample_mask : np.ndarray, shape=[n_total_samples]
|
||||
An ndarray where ``n_total_in_bag`` elements are set to ``True``
|
||||
the others are ``False``.
|
||||
"""
|
||||
cdef float64_t[::1] rand = random_state.uniform(size=n_total_samples)
|
||||
cdef uint8_t[::1] sample_mask = np_zeros((n_total_samples,), dtype=bool)
|
||||
|
||||
cdef intp_t n_bagged = 0
|
||||
cdef intp_t i = 0
|
||||
|
||||
for i in range(n_total_samples):
|
||||
if rand[i] * (n_total_samples - i) < (n_total_in_bag - n_bagged):
|
||||
sample_mask[i] = 1
|
||||
n_bagged += 1
|
||||
|
||||
return sample_mask.base
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from libc.stdlib cimport free
|
||||
from libc.string cimport memset
|
||||
|
||||
import numpy as np
|
||||
from scipy.sparse import issparse
|
||||
|
||||
from ..utils._typedefs cimport float32_t, float64_t, intp_t, int32_t, uint8_t
|
||||
# Note: _tree uses cimport numpy, cnp.import_array, so we need to include
|
||||
# numpy headers in the build configuration of this extension
|
||||
from ..tree._tree cimport Node
|
||||
from ..tree._tree cimport Tree
|
||||
from ..tree._utils cimport safe_realloc
|
||||
|
||||
|
||||
# no namespace lookup for numpy dtype and array creation
|
||||
from numpy import zeros as np_zeros
|
||||
|
||||
|
||||
# constant to mark tree leafs
|
||||
cdef intp_t TREE_LEAF = -1
|
||||
|
||||
cdef void _predict_regression_tree_inplace_fast_dense(
|
||||
const float32_t[:, ::1] X,
|
||||
Node* root_node,
|
||||
double *value,
|
||||
double scale,
|
||||
Py_ssize_t k,
|
||||
float64_t[:, :] out
|
||||
) noexcept nogil:
|
||||
"""Predicts output for regression tree and stores it in ``out[i, k]``.
|
||||
|
||||
This function operates directly on the data arrays of the tree
|
||||
data structures. This is 5x faster than the variant above because
|
||||
it allows us to avoid buffer validation.
|
||||
|
||||
The function assumes that the ndarray that wraps ``X`` is
|
||||
c-continuous.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : float32_t 2d memory view
|
||||
The memory view on the data ndarray of the input ``X``.
|
||||
Assumes that the array is c-continuous.
|
||||
root_node : tree Node pointer
|
||||
Pointer to the main node array of the :class:``sklearn.tree.Tree``.
|
||||
value : np.float64_t pointer
|
||||
The pointer to the data array of the ``value`` array attribute
|
||||
of the :class:``sklearn.tree.Tree``.
|
||||
scale : double
|
||||
A constant to scale the predictions.
|
||||
k : int
|
||||
The index of the tree output to be predicted. Must satisfy
|
||||
0 <= ``k`` < ``K``.
|
||||
out : memory view on array of type np.float64_t
|
||||
The data array where the predictions are stored.
|
||||
``out`` is assumed to be a two-dimensional array of
|
||||
shape ``(n_samples, K)``.
|
||||
"""
|
||||
cdef intp_t n_samples = X.shape[0]
|
||||
cdef Py_ssize_t i
|
||||
cdef Node *node
|
||||
for i in range(n_samples):
|
||||
node = root_node
|
||||
# While node not a leaf
|
||||
while node.left_child != TREE_LEAF:
|
||||
if X[i, node.feature] <= node.threshold:
|
||||
node = root_node + node.left_child
|
||||
else:
|
||||
node = root_node + node.right_child
|
||||
out[i, k] += scale * value[node - root_node]
|
||||
|
||||
|
||||
def _predict_regression_tree_stages_sparse(
|
||||
object[:, :] estimators,
|
||||
object X,
|
||||
double scale,
|
||||
float64_t[:, :] out
|
||||
):
|
||||
"""Predicts output for regression tree inplace and adds scaled value to ``out[i, k]``.
|
||||
|
||||
The function assumes that the ndarray that wraps ``X`` is csr_matrix.
|
||||
"""
|
||||
cdef const float32_t[::1] X_data = X.data
|
||||
cdef const int32_t[::1] X_indices = X.indices
|
||||
cdef const int32_t[::1] X_indptr = X.indptr
|
||||
|
||||
cdef intp_t n_samples = X.shape[0]
|
||||
cdef intp_t n_features = X.shape[1]
|
||||
cdef intp_t n_stages = estimators.shape[0]
|
||||
cdef intp_t n_outputs = estimators.shape[1]
|
||||
|
||||
# Indices and temporary variables
|
||||
cdef intp_t sample_i
|
||||
cdef intp_t feature_i
|
||||
cdef intp_t stage_i
|
||||
cdef intp_t output_i
|
||||
cdef Node *root_node = NULL
|
||||
cdef Node *node = NULL
|
||||
cdef double *value = NULL
|
||||
|
||||
cdef Tree tree
|
||||
cdef Node** nodes = NULL
|
||||
cdef double** values = NULL
|
||||
safe_realloc(&nodes, n_stages * n_outputs)
|
||||
safe_realloc(&values, n_stages * n_outputs)
|
||||
for stage_i in range(n_stages):
|
||||
for output_i in range(n_outputs):
|
||||
tree = estimators[stage_i, output_i].tree_
|
||||
nodes[stage_i * n_outputs + output_i] = tree.nodes
|
||||
values[stage_i * n_outputs + output_i] = tree.value
|
||||
|
||||
# Initialize auxiliary data-structure
|
||||
cdef float32_t feature_value = 0.
|
||||
cdef float32_t* X_sample = NULL
|
||||
|
||||
# feature_to_sample as a data structure records the last seen sample
|
||||
# for each feature; functionally, it is an efficient way to identify
|
||||
# which features are nonzero in the present sample.
|
||||
cdef intp_t* feature_to_sample = NULL
|
||||
|
||||
safe_realloc(&X_sample, n_features)
|
||||
safe_realloc(&feature_to_sample, n_features)
|
||||
|
||||
memset(feature_to_sample, -1, n_features * sizeof(intp_t))
|
||||
|
||||
# Cycle through all samples
|
||||
for sample_i in range(n_samples):
|
||||
for feature_i in range(X_indptr[sample_i], X_indptr[sample_i + 1]):
|
||||
feature_to_sample[X_indices[feature_i]] = sample_i
|
||||
X_sample[X_indices[feature_i]] = X_data[feature_i]
|
||||
|
||||
# Cycle through all stages
|
||||
for stage_i in range(n_stages):
|
||||
# Cycle through all trees
|
||||
for output_i in range(n_outputs):
|
||||
root_node = nodes[stage_i * n_outputs + output_i]
|
||||
value = values[stage_i * n_outputs + output_i]
|
||||
node = root_node
|
||||
|
||||
# While node not a leaf
|
||||
while node.left_child != TREE_LEAF:
|
||||
# ... and node.right_child != TREE_LEAF:
|
||||
if feature_to_sample[node.feature] == sample_i:
|
||||
feature_value = X_sample[node.feature]
|
||||
else:
|
||||
feature_value = 0.
|
||||
|
||||
if feature_value <= node.threshold:
|
||||
node = root_node + node.left_child
|
||||
else:
|
||||
node = root_node + node.right_child
|
||||
out[sample_i, output_i] += scale * value[node - root_node]
|
||||
|
||||
# Free auxiliary arrays
|
||||
free(X_sample)
|
||||
free(feature_to_sample)
|
||||
free(nodes)
|
||||
free(values)
|
||||
|
||||
|
||||
def predict_stages(
|
||||
object[:, :] estimators,
|
||||
object X,
|
||||
double scale,
|
||||
float64_t[:, :] out
|
||||
):
|
||||
"""Add predictions of ``estimators`` to ``out``.
|
||||
|
||||
Each estimator is scaled by ``scale`` before its prediction
|
||||
is added to ``out``.
|
||||
"""
|
||||
cdef Py_ssize_t i
|
||||
cdef Py_ssize_t k
|
||||
cdef Py_ssize_t n_estimators = estimators.shape[0]
|
||||
cdef Py_ssize_t K = estimators.shape[1]
|
||||
cdef Tree tree
|
||||
|
||||
if issparse(X):
|
||||
if X.format != 'csr':
|
||||
raise ValueError("When X is a sparse matrix, a CSR format is"
|
||||
" expected, got {!r}".format(type(X)))
|
||||
_predict_regression_tree_stages_sparse(
|
||||
estimators=estimators, X=X, scale=scale, out=out
|
||||
)
|
||||
else:
|
||||
if not isinstance(X, np.ndarray) or np.isfortran(X):
|
||||
raise ValueError(f"X should be C-ordered np.ndarray, got {type(X)}")
|
||||
|
||||
for i in range(n_estimators):
|
||||
for k in range(K):
|
||||
tree = estimators[i, k].tree_
|
||||
|
||||
# avoid buffer validation by casting to ndarray
|
||||
# and get data pointer
|
||||
# need brackets because of casting operator priority
|
||||
_predict_regression_tree_inplace_fast_dense(
|
||||
X=X,
|
||||
root_node=tree.nodes,
|
||||
value=tree.value,
|
||||
scale=scale,
|
||||
k=k,
|
||||
out=out
|
||||
)
|
||||
# out[:, k] += scale * tree.predict(X).ravel()
|
||||
|
||||
|
||||
def predict_stage(
|
||||
object[:, :] estimators,
|
||||
int stage,
|
||||
object X,
|
||||
double scale,
|
||||
float64_t[:, :] out
|
||||
):
|
||||
"""Add predictions of ``estimators[stage]`` to ``out``.
|
||||
|
||||
Each estimator in the stage is scaled by ``scale`` before
|
||||
its prediction is added to ``out``.
|
||||
"""
|
||||
return predict_stages(
|
||||
estimators=estimators[stage:stage + 1], X=X, scale=scale, out=out
|
||||
)
|
||||
|
||||
|
||||
def _random_sample_mask(
|
||||
intp_t n_total_samples,
|
||||
intp_t n_total_in_bag,
|
||||
random_state
|
||||
):
|
||||
"""Create a random sample mask where ``n_total_in_bag`` elements are set.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n_total_samples : int
|
||||
The length of the resulting mask.
|
||||
|
||||
n_total_in_bag : int
|
||||
The number of elements in the sample mask which are set to 1.
|
||||
|
||||
random_state : RandomState
|
||||
A numpy ``RandomState`` object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
sample_mask : np.ndarray, shape=[n_total_samples]
|
||||
An ndarray where ``n_total_in_bag`` elements are set to ``True``
|
||||
the others are ``False``.
|
||||
"""
|
||||
cdef float64_t[::1] rand = random_state.uniform(size=n_total_samples)
|
||||
cdef uint8_t[::1] sample_mask = np_zeros((n_total_samples,), dtype=bool)
|
||||
|
||||
cdef intp_t n_bagged = 0
|
||||
cdef intp_t i = 0
|
||||
|
||||
for i in range(n_total_samples):
|
||||
if rand[i] * (n_total_samples - i) < (n_total_in_bag - n_bagged):
|
||||
sample_mask[i] = 1
|
||||
n_bagged += 1
|
||||
|
||||
return sample_mask.base
|
||||
|
||||
+85
-85
@@ -1,85 +1,85 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from cython.parallel import prange
|
||||
from libc.math cimport isnan
|
||||
|
||||
from .common cimport X_DTYPE_C, X_BINNED_DTYPE_C
|
||||
from ...utils._typedefs cimport uint8_t
|
||||
|
||||
|
||||
def _map_to_bins(const X_DTYPE_C [:, :] data,
|
||||
list binning_thresholds,
|
||||
const uint8_t[::1] is_categorical,
|
||||
const uint8_t missing_values_bin_idx,
|
||||
int n_threads,
|
||||
X_BINNED_DTYPE_C [::1, :] binned):
|
||||
"""Bin continuous and categorical values to discrete integer-coded levels.
|
||||
|
||||
A given value x is mapped into bin value i iff
|
||||
thresholds[i - 1] < x <= thresholds[i]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : ndarray, shape (n_samples, n_features)
|
||||
The data to bin.
|
||||
binning_thresholds : list of arrays
|
||||
For each feature, stores the increasing numeric values that are
|
||||
used to separate the bins.
|
||||
is_categorical : ndarray of uint8_t of shape (n_features,)
|
||||
Indicates categorical features.
|
||||
n_threads : int
|
||||
Number of OpenMP threads to use.
|
||||
binned : ndarray, shape (n_samples, n_features)
|
||||
Output array, must be fortran aligned.
|
||||
"""
|
||||
cdef:
|
||||
int feature_idx
|
||||
|
||||
for feature_idx in range(data.shape[1]):
|
||||
_map_col_to_bins(
|
||||
data[:, feature_idx],
|
||||
binning_thresholds[feature_idx],
|
||||
is_categorical[feature_idx],
|
||||
missing_values_bin_idx,
|
||||
n_threads,
|
||||
binned[:, feature_idx]
|
||||
)
|
||||
|
||||
|
||||
cdef void _map_col_to_bins(
|
||||
const X_DTYPE_C [:] data,
|
||||
const X_DTYPE_C [:] binning_thresholds,
|
||||
const uint8_t is_categorical,
|
||||
const uint8_t missing_values_bin_idx,
|
||||
int n_threads,
|
||||
X_BINNED_DTYPE_C [:] binned
|
||||
):
|
||||
"""Binary search to find the bin index for each value in the data."""
|
||||
cdef:
|
||||
int i
|
||||
int left
|
||||
int right
|
||||
int middle
|
||||
|
||||
for i in prange(data.shape[0], schedule='static', nogil=True,
|
||||
num_threads=n_threads):
|
||||
if (
|
||||
isnan(data[i]) or
|
||||
# To follow LightGBM's conventions, negative values for
|
||||
# categorical features are considered as missing values.
|
||||
(is_categorical and data[i] < 0)
|
||||
):
|
||||
binned[i] = missing_values_bin_idx
|
||||
else:
|
||||
# for known values, use binary search
|
||||
left, right = 0, binning_thresholds.shape[0]
|
||||
while left < right:
|
||||
# equal to (right + left - 1) // 2 but avoids overflow
|
||||
middle = left + (right - left - 1) // 2
|
||||
if data[i] <= binning_thresholds[middle]:
|
||||
right = middle
|
||||
else:
|
||||
left = middle + 1
|
||||
|
||||
binned[i] = left
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from cython.parallel import prange
|
||||
from libc.math cimport isnan
|
||||
|
||||
from .common cimport X_DTYPE_C, X_BINNED_DTYPE_C
|
||||
from ...utils._typedefs cimport uint8_t
|
||||
|
||||
|
||||
def _map_to_bins(const X_DTYPE_C [:, :] data,
|
||||
list binning_thresholds,
|
||||
const uint8_t[::1] is_categorical,
|
||||
const uint8_t missing_values_bin_idx,
|
||||
int n_threads,
|
||||
X_BINNED_DTYPE_C [::1, :] binned):
|
||||
"""Bin continuous and categorical values to discrete integer-coded levels.
|
||||
|
||||
A given value x is mapped into bin value i iff
|
||||
thresholds[i - 1] < x <= thresholds[i]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : ndarray, shape (n_samples, n_features)
|
||||
The data to bin.
|
||||
binning_thresholds : list of arrays
|
||||
For each feature, stores the increasing numeric values that are
|
||||
used to separate the bins.
|
||||
is_categorical : ndarray of uint8_t of shape (n_features,)
|
||||
Indicates categorical features.
|
||||
n_threads : int
|
||||
Number of OpenMP threads to use.
|
||||
binned : ndarray, shape (n_samples, n_features)
|
||||
Output array, must be fortran aligned.
|
||||
"""
|
||||
cdef:
|
||||
int feature_idx
|
||||
|
||||
for feature_idx in range(data.shape[1]):
|
||||
_map_col_to_bins(
|
||||
data[:, feature_idx],
|
||||
binning_thresholds[feature_idx],
|
||||
is_categorical[feature_idx],
|
||||
missing_values_bin_idx,
|
||||
n_threads,
|
||||
binned[:, feature_idx]
|
||||
)
|
||||
|
||||
|
||||
cdef void _map_col_to_bins(
|
||||
const X_DTYPE_C [:] data,
|
||||
const X_DTYPE_C [:] binning_thresholds,
|
||||
const uint8_t is_categorical,
|
||||
const uint8_t missing_values_bin_idx,
|
||||
int n_threads,
|
||||
X_BINNED_DTYPE_C [:] binned
|
||||
):
|
||||
"""Binary search to find the bin index for each value in the data."""
|
||||
cdef:
|
||||
int i
|
||||
int left
|
||||
int right
|
||||
int middle
|
||||
|
||||
for i in prange(data.shape[0], schedule='static', nogil=True,
|
||||
num_threads=n_threads):
|
||||
if (
|
||||
isnan(data[i]) or
|
||||
# To follow LightGBM's conventions, negative values for
|
||||
# categorical features are considered as missing values.
|
||||
(is_categorical and data[i] < 0)
|
||||
):
|
||||
binned[i] = missing_values_bin_idx
|
||||
else:
|
||||
# for known values, use binary search
|
||||
left, right = 0, binning_thresholds.shape[0]
|
||||
while left < right:
|
||||
# equal to (right + left - 1) // 2 but avoids overflow
|
||||
middle = left + (right - left - 1) // 2
|
||||
if data[i] <= binning_thresholds[middle]:
|
||||
right = middle
|
||||
else:
|
||||
left = middle + 1
|
||||
|
||||
binned[i] = left
|
||||
|
||||
+20
-20
@@ -1,20 +1,20 @@
|
||||
from .common cimport X_BINNED_DTYPE_C
|
||||
from .common cimport BITSET_DTYPE_C
|
||||
from .common cimport BITSET_INNER_DTYPE_C
|
||||
from .common cimport X_DTYPE_C
|
||||
from ...utils._typedefs cimport uint8_t
|
||||
|
||||
|
||||
cdef void init_bitset(BITSET_DTYPE_C bitset) noexcept nogil
|
||||
|
||||
cdef void set_bitset(BITSET_DTYPE_C bitset, X_BINNED_DTYPE_C val) noexcept nogil
|
||||
|
||||
cdef uint8_t in_bitset(BITSET_DTYPE_C bitset, X_BINNED_DTYPE_C val) noexcept nogil
|
||||
|
||||
cpdef uint8_t in_bitset_memoryview(const BITSET_INNER_DTYPE_C[:] bitset,
|
||||
X_BINNED_DTYPE_C val) noexcept nogil
|
||||
|
||||
cdef uint8_t in_bitset_2d_memoryview(
|
||||
const BITSET_INNER_DTYPE_C[:, :] bitset,
|
||||
X_BINNED_DTYPE_C val,
|
||||
unsigned int row) noexcept nogil
|
||||
from .common cimport X_BINNED_DTYPE_C
|
||||
from .common cimport BITSET_DTYPE_C
|
||||
from .common cimport BITSET_INNER_DTYPE_C
|
||||
from .common cimport X_DTYPE_C
|
||||
from ...utils._typedefs cimport uint8_t
|
||||
|
||||
|
||||
cdef void init_bitset(BITSET_DTYPE_C bitset) noexcept nogil
|
||||
|
||||
cdef void set_bitset(BITSET_DTYPE_C bitset, X_BINNED_DTYPE_C val) noexcept nogil
|
||||
|
||||
cdef uint8_t in_bitset(BITSET_DTYPE_C bitset, X_BINNED_DTYPE_C val) noexcept nogil
|
||||
|
||||
cpdef uint8_t in_bitset_memoryview(const BITSET_INNER_DTYPE_C[:] bitset,
|
||||
X_BINNED_DTYPE_C val) noexcept nogil
|
||||
|
||||
cdef uint8_t in_bitset_2d_memoryview(
|
||||
const BITSET_INNER_DTYPE_C[:, :] bitset,
|
||||
X_BINNED_DTYPE_C val,
|
||||
unsigned int row) noexcept nogil
|
||||
|
||||
+65
-65
@@ -1,65 +1,65 @@
|
||||
from .common cimport BITSET_INNER_DTYPE_C
|
||||
from .common cimport BITSET_DTYPE_C
|
||||
from .common cimport X_DTYPE_C
|
||||
from .common cimport X_BINNED_DTYPE_C
|
||||
from ...utils._typedefs cimport uint8_t
|
||||
|
||||
|
||||
# A bitset is a data structure used to represent sets of integers in [0, n]. We
|
||||
# use them to represent sets of features indices (e.g. features that go to the
|
||||
# left child, or features that are categorical). For familiarity with bitsets
|
||||
# and bitwise operations:
|
||||
# https://en.wikipedia.org/wiki/Bit_array
|
||||
# https://en.wikipedia.org/wiki/Bitwise_operation
|
||||
|
||||
|
||||
cdef inline void init_bitset(BITSET_DTYPE_C bitset) noexcept nogil: # OUT
|
||||
cdef:
|
||||
unsigned int i
|
||||
|
||||
for i in range(8):
|
||||
bitset[i] = 0
|
||||
|
||||
|
||||
cdef inline void set_bitset(BITSET_DTYPE_C bitset, # OUT
|
||||
X_BINNED_DTYPE_C val) noexcept nogil:
|
||||
bitset[val // 32] |= (1 << (val % 32))
|
||||
|
||||
|
||||
cdef inline uint8_t in_bitset(BITSET_DTYPE_C bitset,
|
||||
X_BINNED_DTYPE_C val) noexcept nogil:
|
||||
return (bitset[val // 32] >> (val % 32)) & 1
|
||||
|
||||
|
||||
cpdef inline uint8_t in_bitset_memoryview(const BITSET_INNER_DTYPE_C[:] bitset,
|
||||
X_BINNED_DTYPE_C val) noexcept nogil:
|
||||
return (bitset[val // 32] >> (val % 32)) & 1
|
||||
|
||||
|
||||
cdef inline uint8_t in_bitset_2d_memoryview(const BITSET_INNER_DTYPE_C[:, :] bitset,
|
||||
X_BINNED_DTYPE_C val,
|
||||
unsigned int row) noexcept nogil:
|
||||
# Same as above but works on 2d memory views to avoid the creation of 1d
|
||||
# memory views. See https://github.com/scikit-learn/scikit-learn/issues/17299
|
||||
return (bitset[row, val // 32] >> (val % 32)) & 1
|
||||
|
||||
|
||||
cpdef inline void set_bitset_memoryview(BITSET_INNER_DTYPE_C[:] bitset, # OUT
|
||||
X_BINNED_DTYPE_C val):
|
||||
bitset[val // 32] |= (1 << (val % 32))
|
||||
|
||||
|
||||
def set_raw_bitset_from_binned_bitset(BITSET_INNER_DTYPE_C[:] raw_bitset, # OUT
|
||||
BITSET_INNER_DTYPE_C[:] binned_bitset,
|
||||
X_DTYPE_C[:] categories):
|
||||
"""Set the raw_bitset from the values of the binned bitset
|
||||
|
||||
categories is a mapping from binned category value to raw category value.
|
||||
"""
|
||||
cdef:
|
||||
int binned_cat_value
|
||||
X_DTYPE_C raw_cat_value
|
||||
|
||||
for binned_cat_value, raw_cat_value in enumerate(categories):
|
||||
if in_bitset_memoryview(binned_bitset, binned_cat_value):
|
||||
set_bitset_memoryview(raw_bitset, <X_BINNED_DTYPE_C>raw_cat_value)
|
||||
from .common cimport BITSET_INNER_DTYPE_C
|
||||
from .common cimport BITSET_DTYPE_C
|
||||
from .common cimport X_DTYPE_C
|
||||
from .common cimport X_BINNED_DTYPE_C
|
||||
from ...utils._typedefs cimport uint8_t
|
||||
|
||||
|
||||
# A bitset is a data structure used to represent sets of integers in [0, n]. We
|
||||
# use them to represent sets of features indices (e.g. features that go to the
|
||||
# left child, or features that are categorical). For familiarity with bitsets
|
||||
# and bitwise operations:
|
||||
# https://en.wikipedia.org/wiki/Bit_array
|
||||
# https://en.wikipedia.org/wiki/Bitwise_operation
|
||||
|
||||
|
||||
cdef inline void init_bitset(BITSET_DTYPE_C bitset) noexcept nogil: # OUT
|
||||
cdef:
|
||||
unsigned int i
|
||||
|
||||
for i in range(8):
|
||||
bitset[i] = 0
|
||||
|
||||
|
||||
cdef inline void set_bitset(BITSET_DTYPE_C bitset, # OUT
|
||||
X_BINNED_DTYPE_C val) noexcept nogil:
|
||||
bitset[val // 32] |= (1 << (val % 32))
|
||||
|
||||
|
||||
cdef inline uint8_t in_bitset(BITSET_DTYPE_C bitset,
|
||||
X_BINNED_DTYPE_C val) noexcept nogil:
|
||||
return (bitset[val // 32] >> (val % 32)) & 1
|
||||
|
||||
|
||||
cpdef inline uint8_t in_bitset_memoryview(const BITSET_INNER_DTYPE_C[:] bitset,
|
||||
X_BINNED_DTYPE_C val) noexcept nogil:
|
||||
return (bitset[val // 32] >> (val % 32)) & 1
|
||||
|
||||
|
||||
cdef inline uint8_t in_bitset_2d_memoryview(const BITSET_INNER_DTYPE_C[:, :] bitset,
|
||||
X_BINNED_DTYPE_C val,
|
||||
unsigned int row) noexcept nogil:
|
||||
# Same as above but works on 2d memory views to avoid the creation of 1d
|
||||
# memory views. See https://github.com/scikit-learn/scikit-learn/issues/17299
|
||||
return (bitset[row, val // 32] >> (val % 32)) & 1
|
||||
|
||||
|
||||
cpdef inline void set_bitset_memoryview(BITSET_INNER_DTYPE_C[:] bitset, # OUT
|
||||
X_BINNED_DTYPE_C val):
|
||||
bitset[val // 32] |= (1 << (val % 32))
|
||||
|
||||
|
||||
def set_raw_bitset_from_binned_bitset(BITSET_INNER_DTYPE_C[:] raw_bitset, # OUT
|
||||
BITSET_INNER_DTYPE_C[:] binned_bitset,
|
||||
X_DTYPE_C[:] categories):
|
||||
"""Set the raw_bitset from the values of the binned bitset
|
||||
|
||||
categories is a mapping from binned category value to raw category value.
|
||||
"""
|
||||
cdef:
|
||||
int binned_cat_value
|
||||
X_DTYPE_C raw_cat_value
|
||||
|
||||
for binned_cat_value, raw_cat_value in enumerate(categories):
|
||||
if in_bitset_memoryview(binned_bitset, binned_cat_value):
|
||||
set_bitset_memoryview(raw_bitset, <X_BINNED_DTYPE_C>raw_cat_value)
|
||||
|
||||
+59
-59
@@ -1,59 +1,59 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from cython.parallel import prange
|
||||
import numpy as np
|
||||
|
||||
from .common import Y_DTYPE
|
||||
from .common cimport Y_DTYPE_C
|
||||
|
||||
|
||||
def _update_raw_predictions(
|
||||
Y_DTYPE_C [::1] raw_predictions, # OUT
|
||||
grower,
|
||||
n_threads,
|
||||
):
|
||||
"""Update raw_predictions with the predictions of the newest tree.
|
||||
|
||||
This is equivalent to (and much faster than):
|
||||
raw_predictions += last_estimator.predict(X_train)
|
||||
|
||||
It's only possible for data X_train that is used to train the trees (it
|
||||
isn't usable for e.g. X_val).
|
||||
"""
|
||||
cdef:
|
||||
unsigned int [::1] starts # start of each leaf in partition
|
||||
unsigned int [::1] stops # end of each leaf in partition
|
||||
Y_DTYPE_C [::1] values # value of each leaf
|
||||
const unsigned int [::1] partition = grower.splitter.partition
|
||||
list leaves
|
||||
|
||||
leaves = grower.finalized_leaves
|
||||
starts = np.array([leaf.partition_start for leaf in leaves],
|
||||
dtype=np.uint32)
|
||||
stops = np.array([leaf.partition_stop for leaf in leaves],
|
||||
dtype=np.uint32)
|
||||
values = np.array([leaf.value for leaf in leaves], dtype=Y_DTYPE)
|
||||
|
||||
_update_raw_predictions_helper(raw_predictions, starts, stops, partition,
|
||||
values, n_threads)
|
||||
|
||||
|
||||
cdef inline void _update_raw_predictions_helper(
|
||||
Y_DTYPE_C [::1] raw_predictions, # OUT
|
||||
const unsigned int [::1] starts,
|
||||
const unsigned int [::1] stops,
|
||||
const unsigned int [::1] partition,
|
||||
const Y_DTYPE_C [::1] values,
|
||||
int n_threads,
|
||||
):
|
||||
|
||||
cdef:
|
||||
unsigned int position
|
||||
int leaf_idx
|
||||
int n_leaves = starts.shape[0]
|
||||
|
||||
for leaf_idx in prange(n_leaves, schedule='static', nogil=True,
|
||||
num_threads=n_threads):
|
||||
for position in range(starts[leaf_idx], stops[leaf_idx]):
|
||||
raw_predictions[partition[position]] += values[leaf_idx]
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from cython.parallel import prange
|
||||
import numpy as np
|
||||
|
||||
from .common import Y_DTYPE
|
||||
from .common cimport Y_DTYPE_C
|
||||
|
||||
|
||||
def _update_raw_predictions(
|
||||
Y_DTYPE_C [::1] raw_predictions, # OUT
|
||||
grower,
|
||||
n_threads,
|
||||
):
|
||||
"""Update raw_predictions with the predictions of the newest tree.
|
||||
|
||||
This is equivalent to (and much faster than):
|
||||
raw_predictions += last_estimator.predict(X_train)
|
||||
|
||||
It's only possible for data X_train that is used to train the trees (it
|
||||
isn't usable for e.g. X_val).
|
||||
"""
|
||||
cdef:
|
||||
unsigned int [::1] starts # start of each leaf in partition
|
||||
unsigned int [::1] stops # end of each leaf in partition
|
||||
Y_DTYPE_C [::1] values # value of each leaf
|
||||
const unsigned int [::1] partition = grower.splitter.partition
|
||||
list leaves
|
||||
|
||||
leaves = grower.finalized_leaves
|
||||
starts = np.array([leaf.partition_start for leaf in leaves],
|
||||
dtype=np.uint32)
|
||||
stops = np.array([leaf.partition_stop for leaf in leaves],
|
||||
dtype=np.uint32)
|
||||
values = np.array([leaf.value for leaf in leaves], dtype=Y_DTYPE)
|
||||
|
||||
_update_raw_predictions_helper(raw_predictions, starts, stops, partition,
|
||||
values, n_threads)
|
||||
|
||||
|
||||
cdef inline void _update_raw_predictions_helper(
|
||||
Y_DTYPE_C [::1] raw_predictions, # OUT
|
||||
const unsigned int [::1] starts,
|
||||
const unsigned int [::1] stops,
|
||||
const unsigned int [::1] partition,
|
||||
const Y_DTYPE_C [::1] values,
|
||||
int n_threads,
|
||||
):
|
||||
|
||||
cdef:
|
||||
unsigned int position
|
||||
int leaf_idx
|
||||
int n_leaves = starts.shape[0]
|
||||
|
||||
for leaf_idx in prange(n_leaves, schedule='static', nogil=True,
|
||||
num_threads=n_threads):
|
||||
for position in range(starts[leaf_idx], stops[leaf_idx]):
|
||||
raw_predictions[partition[position]] += values[leaf_idx]
|
||||
|
||||
+256
-256
@@ -1,256 +1,256 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from cython.parallel import prange
|
||||
from libc.math cimport isnan
|
||||
import numpy as np
|
||||
|
||||
from ...utils._typedefs cimport intp_t, uint8_t
|
||||
from .common cimport X_DTYPE_C
|
||||
from .common cimport Y_DTYPE_C
|
||||
from .common import Y_DTYPE
|
||||
from .common cimport X_BINNED_DTYPE_C
|
||||
from .common cimport BITSET_INNER_DTYPE_C
|
||||
from .common cimport node_struct
|
||||
from ._bitset cimport in_bitset_2d_memoryview
|
||||
|
||||
|
||||
def _predict_from_raw_data( # raw data = non-binned data
|
||||
const node_struct [:] nodes,
|
||||
const X_DTYPE_C [:, :] numeric_data,
|
||||
const BITSET_INNER_DTYPE_C [:, ::1] raw_left_cat_bitsets,
|
||||
const BITSET_INNER_DTYPE_C [:, ::1] known_cat_bitsets,
|
||||
const unsigned int [::1] f_idx_map,
|
||||
int n_threads,
|
||||
Y_DTYPE_C [:] out):
|
||||
|
||||
cdef:
|
||||
int i
|
||||
|
||||
for i in prange(numeric_data.shape[0], schedule='static', nogil=True,
|
||||
num_threads=n_threads):
|
||||
out[i] = _predict_one_from_raw_data(
|
||||
nodes, numeric_data, raw_left_cat_bitsets,
|
||||
known_cat_bitsets,
|
||||
f_idx_map, i)
|
||||
|
||||
|
||||
cdef inline Y_DTYPE_C _predict_one_from_raw_data(
|
||||
const node_struct [:] nodes,
|
||||
const X_DTYPE_C [:, :] numeric_data,
|
||||
const BITSET_INNER_DTYPE_C [:, ::1] raw_left_cat_bitsets,
|
||||
const BITSET_INNER_DTYPE_C [:, ::1] known_cat_bitsets,
|
||||
const unsigned int [::1] f_idx_map,
|
||||
const int row) noexcept nogil:
|
||||
# Need to pass the whole array and the row index, else prange won't work.
|
||||
# See issue Cython #2798
|
||||
|
||||
cdef:
|
||||
node_struct node = nodes[0]
|
||||
unsigned int node_idx = 0
|
||||
X_DTYPE_C data_val
|
||||
|
||||
while True:
|
||||
if node.is_leaf:
|
||||
return node.value
|
||||
|
||||
data_val = numeric_data[row, node.feature_idx]
|
||||
|
||||
if isnan(data_val):
|
||||
if node.missing_go_to_left:
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
elif node.is_categorical:
|
||||
if data_val < 0:
|
||||
# data_val is not in the accepted range, so it is treated as missing value
|
||||
node_idx = node.left if node.missing_go_to_left else node.right
|
||||
elif in_bitset_2d_memoryview(
|
||||
raw_left_cat_bitsets,
|
||||
<X_BINNED_DTYPE_C>data_val,
|
||||
node.bitset_idx):
|
||||
node_idx = node.left
|
||||
elif in_bitset_2d_memoryview(
|
||||
known_cat_bitsets,
|
||||
<X_BINNED_DTYPE_C>data_val,
|
||||
f_idx_map[node.feature_idx]):
|
||||
node_idx = node.right
|
||||
else:
|
||||
# Treat unknown categories as missing.
|
||||
node_idx = node.left if node.missing_go_to_left else node.right
|
||||
else:
|
||||
if data_val <= node.num_threshold:
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
node = nodes[node_idx]
|
||||
|
||||
|
||||
def _predict_from_binned_data(
|
||||
node_struct [:] nodes,
|
||||
const X_BINNED_DTYPE_C [:, :] binned_data,
|
||||
BITSET_INNER_DTYPE_C [:, :] binned_left_cat_bitsets,
|
||||
const uint8_t missing_values_bin_idx,
|
||||
int n_threads,
|
||||
Y_DTYPE_C [:] out):
|
||||
|
||||
cdef:
|
||||
int i
|
||||
|
||||
for i in prange(binned_data.shape[0], schedule='static', nogil=True,
|
||||
num_threads=n_threads):
|
||||
out[i] = _predict_one_from_binned_data(nodes,
|
||||
binned_data,
|
||||
binned_left_cat_bitsets, i,
|
||||
missing_values_bin_idx)
|
||||
|
||||
|
||||
cdef inline Y_DTYPE_C _predict_one_from_binned_data(
|
||||
node_struct [:] nodes,
|
||||
const X_BINNED_DTYPE_C [:, :] binned_data,
|
||||
const BITSET_INNER_DTYPE_C [:, :] binned_left_cat_bitsets,
|
||||
const int row,
|
||||
const uint8_t missing_values_bin_idx) noexcept nogil:
|
||||
# Need to pass the whole array and the row index, else prange won't work.
|
||||
# See issue Cython #2798
|
||||
|
||||
cdef:
|
||||
node_struct node = nodes[0]
|
||||
unsigned int node_idx = 0
|
||||
X_BINNED_DTYPE_C data_val
|
||||
|
||||
while True:
|
||||
if node.is_leaf:
|
||||
return node.value
|
||||
|
||||
data_val = binned_data[row, node.feature_idx]
|
||||
|
||||
if data_val == missing_values_bin_idx:
|
||||
if node.missing_go_to_left:
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
elif node.is_categorical:
|
||||
if in_bitset_2d_memoryview(
|
||||
binned_left_cat_bitsets,
|
||||
data_val,
|
||||
node.bitset_idx):
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
else:
|
||||
if data_val <= node.bin_threshold:
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
node = nodes[node_idx]
|
||||
|
||||
|
||||
def _compute_partial_dependence(
|
||||
node_struct [:] nodes,
|
||||
const X_DTYPE_C [:, ::1] X,
|
||||
const intp_t [:] target_features,
|
||||
Y_DTYPE_C [:] out
|
||||
):
|
||||
"""Partial dependence of the response on the ``target_features`` set.
|
||||
|
||||
For each sample in ``X`` a tree traversal is performed.
|
||||
Each traversal starts from the root with weight 1.0.
|
||||
|
||||
At each non-leaf node that splits on a target feature, either
|
||||
the left child or the right child is visited based on the feature
|
||||
value of the current sample, and the weight is not modified.
|
||||
At each non-leaf node that splits on a complementary feature,
|
||||
both children are visited and the weight is multiplied by the fraction
|
||||
of training samples which went to each child.
|
||||
|
||||
At each leaf, the value of the node is multiplied by the current
|
||||
weight (weights sum to 1 for all visited terminal nodes).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nodes : view on array of PREDICTOR_RECORD_DTYPE, shape (n_nodes)
|
||||
The array representing the predictor tree.
|
||||
X : view on 2d ndarray, shape (n_samples, n_target_features)
|
||||
The grid points on which the partial dependence should be
|
||||
evaluated.
|
||||
target_features : view on 1d ndarray of intp_t, shape (n_target_features)
|
||||
The set of target features for which the partial dependence
|
||||
should be evaluated.
|
||||
out : view on 1d ndarray, shape (n_samples)
|
||||
The value of the partial dependence function on each grid
|
||||
point.
|
||||
"""
|
||||
|
||||
cdef:
|
||||
unsigned int current_node_idx
|
||||
unsigned int [:] node_idx_stack = np.zeros(shape=nodes.shape[0],
|
||||
dtype=np.uint32)
|
||||
Y_DTYPE_C [::1] weight_stack = np.zeros(shape=nodes.shape[0],
|
||||
dtype=Y_DTYPE)
|
||||
node_struct * current_node # pointer to avoid copying attributes
|
||||
|
||||
unsigned int sample_idx
|
||||
intp_t feature_idx
|
||||
unsigned stack_size
|
||||
Y_DTYPE_C left_sample_frac
|
||||
Y_DTYPE_C current_weight
|
||||
Y_DTYPE_C total_weight # used for sanity check only
|
||||
bint is_target_feature
|
||||
|
||||
for sample_idx in range(X.shape[0]):
|
||||
# init stacks for current sample
|
||||
stack_size = 1
|
||||
node_idx_stack[0] = 0 # root node
|
||||
weight_stack[0] = 1 # all the samples are in the root node
|
||||
total_weight = 0
|
||||
|
||||
while stack_size > 0:
|
||||
|
||||
# pop the stack
|
||||
stack_size -= 1
|
||||
current_node_idx = node_idx_stack[stack_size]
|
||||
current_node = &nodes[current_node_idx]
|
||||
|
||||
if current_node.is_leaf:
|
||||
out[sample_idx] += (weight_stack[stack_size] *
|
||||
current_node.value)
|
||||
total_weight += weight_stack[stack_size]
|
||||
else:
|
||||
# determine if the split feature is a target feature
|
||||
is_target_feature = False
|
||||
for feature_idx in range(target_features.shape[0]):
|
||||
if target_features[feature_idx] == current_node.feature_idx:
|
||||
is_target_feature = True
|
||||
break
|
||||
|
||||
if is_target_feature:
|
||||
# In this case, we push left or right child on stack
|
||||
if X[sample_idx, feature_idx] <= current_node.num_threshold:
|
||||
node_idx_stack[stack_size] = current_node.left
|
||||
else:
|
||||
node_idx_stack[stack_size] = current_node.right
|
||||
stack_size += 1
|
||||
else:
|
||||
# In this case, we push both children onto the stack,
|
||||
# and give a weight proportional to the number of
|
||||
# samples going through each branch.
|
||||
|
||||
# push left child
|
||||
node_idx_stack[stack_size] = current_node.left
|
||||
left_sample_frac = (
|
||||
<Y_DTYPE_C> nodes[current_node.left].count /
|
||||
current_node.count)
|
||||
current_weight = weight_stack[stack_size]
|
||||
weight_stack[stack_size] = current_weight * left_sample_frac
|
||||
stack_size += 1
|
||||
|
||||
# push right child
|
||||
node_idx_stack[stack_size] = current_node.right
|
||||
weight_stack[stack_size] = (
|
||||
current_weight * (1 - left_sample_frac))
|
||||
stack_size += 1
|
||||
|
||||
# Sanity check. Should never happen.
|
||||
if not (0.999 < total_weight < 1.001):
|
||||
raise ValueError("Total weight should be 1.0 but was %.9f" %total_weight)
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from cython.parallel import prange
|
||||
from libc.math cimport isnan
|
||||
import numpy as np
|
||||
|
||||
from ...utils._typedefs cimport intp_t, uint8_t
|
||||
from .common cimport X_DTYPE_C
|
||||
from .common cimport Y_DTYPE_C
|
||||
from .common import Y_DTYPE
|
||||
from .common cimport X_BINNED_DTYPE_C
|
||||
from .common cimport BITSET_INNER_DTYPE_C
|
||||
from .common cimport node_struct
|
||||
from ._bitset cimport in_bitset_2d_memoryview
|
||||
|
||||
|
||||
def _predict_from_raw_data( # raw data = non-binned data
|
||||
const node_struct [:] nodes,
|
||||
const X_DTYPE_C [:, :] numeric_data,
|
||||
const BITSET_INNER_DTYPE_C [:, ::1] raw_left_cat_bitsets,
|
||||
const BITSET_INNER_DTYPE_C [:, ::1] known_cat_bitsets,
|
||||
const unsigned int [::1] f_idx_map,
|
||||
int n_threads,
|
||||
Y_DTYPE_C [:] out):
|
||||
|
||||
cdef:
|
||||
int i
|
||||
|
||||
for i in prange(numeric_data.shape[0], schedule='static', nogil=True,
|
||||
num_threads=n_threads):
|
||||
out[i] = _predict_one_from_raw_data(
|
||||
nodes, numeric_data, raw_left_cat_bitsets,
|
||||
known_cat_bitsets,
|
||||
f_idx_map, i)
|
||||
|
||||
|
||||
cdef inline Y_DTYPE_C _predict_one_from_raw_data(
|
||||
const node_struct [:] nodes,
|
||||
const X_DTYPE_C [:, :] numeric_data,
|
||||
const BITSET_INNER_DTYPE_C [:, ::1] raw_left_cat_bitsets,
|
||||
const BITSET_INNER_DTYPE_C [:, ::1] known_cat_bitsets,
|
||||
const unsigned int [::1] f_idx_map,
|
||||
const int row) noexcept nogil:
|
||||
# Need to pass the whole array and the row index, else prange won't work.
|
||||
# See issue Cython #2798
|
||||
|
||||
cdef:
|
||||
node_struct node = nodes[0]
|
||||
unsigned int node_idx = 0
|
||||
X_DTYPE_C data_val
|
||||
|
||||
while True:
|
||||
if node.is_leaf:
|
||||
return node.value
|
||||
|
||||
data_val = numeric_data[row, node.feature_idx]
|
||||
|
||||
if isnan(data_val):
|
||||
if node.missing_go_to_left:
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
elif node.is_categorical:
|
||||
if data_val < 0:
|
||||
# data_val is not in the accepted range, so it is treated as missing value
|
||||
node_idx = node.left if node.missing_go_to_left else node.right
|
||||
elif in_bitset_2d_memoryview(
|
||||
raw_left_cat_bitsets,
|
||||
<X_BINNED_DTYPE_C>data_val,
|
||||
node.bitset_idx):
|
||||
node_idx = node.left
|
||||
elif in_bitset_2d_memoryview(
|
||||
known_cat_bitsets,
|
||||
<X_BINNED_DTYPE_C>data_val,
|
||||
f_idx_map[node.feature_idx]):
|
||||
node_idx = node.right
|
||||
else:
|
||||
# Treat unknown categories as missing.
|
||||
node_idx = node.left if node.missing_go_to_left else node.right
|
||||
else:
|
||||
if data_val <= node.num_threshold:
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
node = nodes[node_idx]
|
||||
|
||||
|
||||
def _predict_from_binned_data(
|
||||
node_struct [:] nodes,
|
||||
const X_BINNED_DTYPE_C [:, :] binned_data,
|
||||
BITSET_INNER_DTYPE_C [:, :] binned_left_cat_bitsets,
|
||||
const uint8_t missing_values_bin_idx,
|
||||
int n_threads,
|
||||
Y_DTYPE_C [:] out):
|
||||
|
||||
cdef:
|
||||
int i
|
||||
|
||||
for i in prange(binned_data.shape[0], schedule='static', nogil=True,
|
||||
num_threads=n_threads):
|
||||
out[i] = _predict_one_from_binned_data(nodes,
|
||||
binned_data,
|
||||
binned_left_cat_bitsets, i,
|
||||
missing_values_bin_idx)
|
||||
|
||||
|
||||
cdef inline Y_DTYPE_C _predict_one_from_binned_data(
|
||||
node_struct [:] nodes,
|
||||
const X_BINNED_DTYPE_C [:, :] binned_data,
|
||||
const BITSET_INNER_DTYPE_C [:, :] binned_left_cat_bitsets,
|
||||
const int row,
|
||||
const uint8_t missing_values_bin_idx) noexcept nogil:
|
||||
# Need to pass the whole array and the row index, else prange won't work.
|
||||
# See issue Cython #2798
|
||||
|
||||
cdef:
|
||||
node_struct node = nodes[0]
|
||||
unsigned int node_idx = 0
|
||||
X_BINNED_DTYPE_C data_val
|
||||
|
||||
while True:
|
||||
if node.is_leaf:
|
||||
return node.value
|
||||
|
||||
data_val = binned_data[row, node.feature_idx]
|
||||
|
||||
if data_val == missing_values_bin_idx:
|
||||
if node.missing_go_to_left:
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
elif node.is_categorical:
|
||||
if in_bitset_2d_memoryview(
|
||||
binned_left_cat_bitsets,
|
||||
data_val,
|
||||
node.bitset_idx):
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
else:
|
||||
if data_val <= node.bin_threshold:
|
||||
node_idx = node.left
|
||||
else:
|
||||
node_idx = node.right
|
||||
node = nodes[node_idx]
|
||||
|
||||
|
||||
def _compute_partial_dependence(
|
||||
node_struct [:] nodes,
|
||||
const X_DTYPE_C [:, ::1] X,
|
||||
const intp_t [:] target_features,
|
||||
Y_DTYPE_C [:] out
|
||||
):
|
||||
"""Partial dependence of the response on the ``target_features`` set.
|
||||
|
||||
For each sample in ``X`` a tree traversal is performed.
|
||||
Each traversal starts from the root with weight 1.0.
|
||||
|
||||
At each non-leaf node that splits on a target feature, either
|
||||
the left child or the right child is visited based on the feature
|
||||
value of the current sample, and the weight is not modified.
|
||||
At each non-leaf node that splits on a complementary feature,
|
||||
both children are visited and the weight is multiplied by the fraction
|
||||
of training samples which went to each child.
|
||||
|
||||
At each leaf, the value of the node is multiplied by the current
|
||||
weight (weights sum to 1 for all visited terminal nodes).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nodes : view on array of PREDICTOR_RECORD_DTYPE, shape (n_nodes)
|
||||
The array representing the predictor tree.
|
||||
X : view on 2d ndarray, shape (n_samples, n_target_features)
|
||||
The grid points on which the partial dependence should be
|
||||
evaluated.
|
||||
target_features : view on 1d ndarray of intp_t, shape (n_target_features)
|
||||
The set of target features for which the partial dependence
|
||||
should be evaluated.
|
||||
out : view on 1d ndarray, shape (n_samples)
|
||||
The value of the partial dependence function on each grid
|
||||
point.
|
||||
"""
|
||||
|
||||
cdef:
|
||||
unsigned int current_node_idx
|
||||
unsigned int [:] node_idx_stack = np.zeros(shape=nodes.shape[0],
|
||||
dtype=np.uint32)
|
||||
Y_DTYPE_C [::1] weight_stack = np.zeros(shape=nodes.shape[0],
|
||||
dtype=Y_DTYPE)
|
||||
node_struct * current_node # pointer to avoid copying attributes
|
||||
|
||||
unsigned int sample_idx
|
||||
intp_t feature_idx
|
||||
unsigned stack_size
|
||||
Y_DTYPE_C left_sample_frac
|
||||
Y_DTYPE_C current_weight
|
||||
Y_DTYPE_C total_weight # used for sanity check only
|
||||
bint is_target_feature
|
||||
|
||||
for sample_idx in range(X.shape[0]):
|
||||
# init stacks for current sample
|
||||
stack_size = 1
|
||||
node_idx_stack[0] = 0 # root node
|
||||
weight_stack[0] = 1 # all the samples are in the root node
|
||||
total_weight = 0
|
||||
|
||||
while stack_size > 0:
|
||||
|
||||
# pop the stack
|
||||
stack_size -= 1
|
||||
current_node_idx = node_idx_stack[stack_size]
|
||||
current_node = &nodes[current_node_idx]
|
||||
|
||||
if current_node.is_leaf:
|
||||
out[sample_idx] += (weight_stack[stack_size] *
|
||||
current_node.value)
|
||||
total_weight += weight_stack[stack_size]
|
||||
else:
|
||||
# determine if the split feature is a target feature
|
||||
is_target_feature = False
|
||||
for feature_idx in range(target_features.shape[0]):
|
||||
if target_features[feature_idx] == current_node.feature_idx:
|
||||
is_target_feature = True
|
||||
break
|
||||
|
||||
if is_target_feature:
|
||||
# In this case, we push left or right child on stack
|
||||
if X[sample_idx, feature_idx] <= current_node.num_threshold:
|
||||
node_idx_stack[stack_size] = current_node.left
|
||||
else:
|
||||
node_idx_stack[stack_size] = current_node.right
|
||||
stack_size += 1
|
||||
else:
|
||||
# In this case, we push both children onto the stack,
|
||||
# and give a weight proportional to the number of
|
||||
# samples going through each branch.
|
||||
|
||||
# push left child
|
||||
node_idx_stack[stack_size] = current_node.left
|
||||
left_sample_frac = (
|
||||
<Y_DTYPE_C> nodes[current_node.left].count /
|
||||
current_node.count)
|
||||
current_weight = weight_stack[stack_size]
|
||||
weight_stack[stack_size] = current_weight * left_sample_frac
|
||||
stack_size += 1
|
||||
|
||||
# push right child
|
||||
node_idx_stack[stack_size] = current_node.right
|
||||
weight_stack[stack_size] = (
|
||||
current_weight * (1 - left_sample_frac))
|
||||
stack_size += 1
|
||||
|
||||
# Sanity check. Should never happen.
|
||||
if not (0.999 < total_weight < 1.001):
|
||||
raise ValueError("Total weight should be 1.0 but was %.9f" %total_weight)
|
||||
|
||||
+43
-43
@@ -1,43 +1,43 @@
|
||||
from ...utils._typedefs cimport float32_t, float64_t, intp_t, uint8_t, uint32_t
|
||||
|
||||
|
||||
ctypedef float64_t X_DTYPE_C
|
||||
ctypedef uint8_t X_BINNED_DTYPE_C
|
||||
ctypedef float64_t Y_DTYPE_C
|
||||
ctypedef float32_t G_H_DTYPE_C
|
||||
ctypedef uint32_t BITSET_INNER_DTYPE_C
|
||||
ctypedef BITSET_INNER_DTYPE_C[8] BITSET_DTYPE_C
|
||||
|
||||
|
||||
cdef packed struct hist_struct:
|
||||
# Same as histogram dtype but we need a struct to declare views. It needs
|
||||
# to be packed since by default numpy dtypes aren't aligned
|
||||
Y_DTYPE_C sum_gradients
|
||||
Y_DTYPE_C sum_hessians
|
||||
unsigned int count
|
||||
|
||||
|
||||
cdef packed struct node_struct:
|
||||
# Equivalent struct to PREDICTOR_RECORD_DTYPE to use in memory views. It
|
||||
# needs to be packed since by default numpy dtypes aren't aligned
|
||||
Y_DTYPE_C value
|
||||
unsigned int count
|
||||
intp_t feature_idx
|
||||
X_DTYPE_C num_threshold
|
||||
uint8_t missing_go_to_left
|
||||
unsigned int left
|
||||
unsigned int right
|
||||
Y_DTYPE_C gain
|
||||
unsigned int depth
|
||||
uint8_t is_leaf
|
||||
X_BINNED_DTYPE_C bin_threshold
|
||||
uint8_t is_categorical
|
||||
# The index of the corresponding bitsets in the Predictor's bitset arrays.
|
||||
# Only used if is_categorical is True
|
||||
unsigned int bitset_idx
|
||||
|
||||
|
||||
cpdef enum MonotonicConstraint:
|
||||
NO_CST = 0
|
||||
POS = 1
|
||||
NEG = -1
|
||||
from ...utils._typedefs cimport float32_t, float64_t, intp_t, uint8_t, uint32_t
|
||||
|
||||
|
||||
ctypedef float64_t X_DTYPE_C
|
||||
ctypedef uint8_t X_BINNED_DTYPE_C
|
||||
ctypedef float64_t Y_DTYPE_C
|
||||
ctypedef float32_t G_H_DTYPE_C
|
||||
ctypedef uint32_t BITSET_INNER_DTYPE_C
|
||||
ctypedef BITSET_INNER_DTYPE_C[8] BITSET_DTYPE_C
|
||||
|
||||
|
||||
cdef packed struct hist_struct:
|
||||
# Same as histogram dtype but we need a struct to declare views. It needs
|
||||
# to be packed since by default numpy dtypes aren't aligned
|
||||
Y_DTYPE_C sum_gradients
|
||||
Y_DTYPE_C sum_hessians
|
||||
unsigned int count
|
||||
|
||||
|
||||
cdef packed struct node_struct:
|
||||
# Equivalent struct to PREDICTOR_RECORD_DTYPE to use in memory views. It
|
||||
# needs to be packed since by default numpy dtypes aren't aligned
|
||||
Y_DTYPE_C value
|
||||
unsigned int count
|
||||
intp_t feature_idx
|
||||
X_DTYPE_C num_threshold
|
||||
uint8_t missing_go_to_left
|
||||
unsigned int left
|
||||
unsigned int right
|
||||
Y_DTYPE_C gain
|
||||
unsigned int depth
|
||||
uint8_t is_leaf
|
||||
X_BINNED_DTYPE_C bin_threshold
|
||||
uint8_t is_categorical
|
||||
# The index of the corresponding bitsets in the Predictor's bitset arrays.
|
||||
# Only used if is_categorical is True
|
||||
unsigned int bitset_idx
|
||||
|
||||
|
||||
cpdef enum MonotonicConstraint:
|
||||
NO_CST = 0
|
||||
POS = 1
|
||||
NEG = -1
|
||||
|
||||
+44
-44
@@ -1,44 +1,44 @@
|
||||
import numpy as np
|
||||
|
||||
# Y_DYTPE is the dtype to which the targets y are converted to. This is also
|
||||
# dtype for leaf values, gains, and sums of gradients / hessians. The gradients
|
||||
# and hessians arrays are stored as floats to avoid using too much memory.
|
||||
Y_DTYPE = np.float64
|
||||
X_DTYPE = np.float64
|
||||
X_BINNED_DTYPE = np.uint8 # hence max_bins == 256
|
||||
# dtype for gradients and hessians arrays
|
||||
G_H_DTYPE = np.float32
|
||||
X_BITSET_INNER_DTYPE = np.uint32
|
||||
|
||||
# Note that we use Y_DTYPE=float64 to avoid issues with floating point precision when
|
||||
# summing gradients and hessians (both float32). Those are difficult to protect via
|
||||
# tools like (Kahan-) Neumaier summation as in CPython, see
|
||||
# https://github.com/python/cpython/issues/100425, or pairwise summation as numpy, see
|
||||
# https://github.com/numpy/numpy/pull/3685, due to the way histograms are summed
|
||||
# (number of additions per bin is not known in advance). See also comment in
|
||||
# _subtract_histograms.
|
||||
HISTOGRAM_DTYPE = np.dtype([
|
||||
('sum_gradients', Y_DTYPE), # sum of sample gradients in bin
|
||||
('sum_hessians', Y_DTYPE), # sum of sample hessians in bin
|
||||
('count', np.uint32), # number of samples in bin
|
||||
])
|
||||
|
||||
PREDICTOR_RECORD_DTYPE = np.dtype([
|
||||
('value', Y_DTYPE),
|
||||
('count', np.uint32),
|
||||
('feature_idx', np.intp),
|
||||
('num_threshold', X_DTYPE),
|
||||
('missing_go_to_left', np.uint8),
|
||||
('left', np.uint32),
|
||||
('right', np.uint32),
|
||||
('gain', Y_DTYPE),
|
||||
('depth', np.uint32),
|
||||
('is_leaf', np.uint8),
|
||||
('bin_threshold', X_BINNED_DTYPE),
|
||||
('is_categorical', np.uint8),
|
||||
# The index of the corresponding bitsets in the Predictor's bitset arrays.
|
||||
# Only used if is_categorical is True
|
||||
('bitset_idx', np.uint32)
|
||||
])
|
||||
|
||||
ALMOST_INF = 1e300 # see LightGBM AvoidInf()
|
||||
import numpy as np
|
||||
|
||||
# Y_DYTPE is the dtype to which the targets y are converted to. This is also
|
||||
# dtype for leaf values, gains, and sums of gradients / hessians. The gradients
|
||||
# and hessians arrays are stored as floats to avoid using too much memory.
|
||||
Y_DTYPE = np.float64
|
||||
X_DTYPE = np.float64
|
||||
X_BINNED_DTYPE = np.uint8 # hence max_bins == 256
|
||||
# dtype for gradients and hessians arrays
|
||||
G_H_DTYPE = np.float32
|
||||
X_BITSET_INNER_DTYPE = np.uint32
|
||||
|
||||
# Note that we use Y_DTYPE=float64 to avoid issues with floating point precision when
|
||||
# summing gradients and hessians (both float32). Those are difficult to protect via
|
||||
# tools like (Kahan-) Neumaier summation as in CPython, see
|
||||
# https://github.com/python/cpython/issues/100425, or pairwise summation as numpy, see
|
||||
# https://github.com/numpy/numpy/pull/3685, due to the way histograms are summed
|
||||
# (number of additions per bin is not known in advance). See also comment in
|
||||
# _subtract_histograms.
|
||||
HISTOGRAM_DTYPE = np.dtype([
|
||||
('sum_gradients', Y_DTYPE), # sum of sample gradients in bin
|
||||
('sum_hessians', Y_DTYPE), # sum of sample hessians in bin
|
||||
('count', np.uint32), # number of samples in bin
|
||||
])
|
||||
|
||||
PREDICTOR_RECORD_DTYPE = np.dtype([
|
||||
('value', Y_DTYPE),
|
||||
('count', np.uint32),
|
||||
('feature_idx', np.intp),
|
||||
('num_threshold', X_DTYPE),
|
||||
('missing_go_to_left', np.uint8),
|
||||
('left', np.uint32),
|
||||
('right', np.uint32),
|
||||
('gain', Y_DTYPE),
|
||||
('depth', np.uint32),
|
||||
('is_leaf', np.uint8),
|
||||
('bin_threshold', X_BINNED_DTYPE),
|
||||
('is_categorical', np.uint8),
|
||||
# The index of the corresponding bitsets in the Predictor's bitset arrays.
|
||||
# Only used if is_categorical is True
|
||||
('bitset_idx', np.uint32)
|
||||
])
|
||||
|
||||
ALMOST_INF = 1e300 # see LightGBM AvoidInf()
|
||||
|
||||
+520
-520
File diff suppressed because it is too large
Load Diff
+20
-20
@@ -1,20 +1,20 @@
|
||||
hist_gradient_boosting_extension_metadata = {
|
||||
'_gradient_boosting': {'sources': [cython_gen.process('_gradient_boosting.pyx')],
|
||||
'dependencies': [openmp_dep]},
|
||||
'histogram': {'sources': [cython_gen.process('histogram.pyx')], 'dependencies': [openmp_dep]},
|
||||
'splitting': {'sources': [cython_gen.process('splitting.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_binning': {'sources': [cython_gen.process('_binning.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_predictor': {'sources': [cython_gen.process('_predictor.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_bitset': {'sources': [cython_gen.process('_bitset.pyx')]},
|
||||
'common': {'sources': [cython_gen.process('common.pyx')]},
|
||||
}
|
||||
|
||||
foreach ext_name, ext_dict : hist_gradient_boosting_extension_metadata
|
||||
py.extension_module(
|
||||
ext_name,
|
||||
ext_dict.get('sources'),
|
||||
dependencies: ext_dict.get('dependencies', []),
|
||||
subdir: 'sklearn/ensemble/_hist_gradient_boosting',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
hist_gradient_boosting_extension_metadata = {
|
||||
'_gradient_boosting': {'sources': [cython_gen.process('_gradient_boosting.pyx')],
|
||||
'dependencies': [openmp_dep]},
|
||||
'histogram': {'sources': [cython_gen.process('histogram.pyx')], 'dependencies': [openmp_dep]},
|
||||
'splitting': {'sources': [cython_gen.process('splitting.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_binning': {'sources': [cython_gen.process('_binning.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_predictor': {'sources': [cython_gen.process('_predictor.pyx')], 'dependencies': [openmp_dep]},
|
||||
'_bitset': {'sources': [cython_gen.process('_bitset.pyx')]},
|
||||
'common': {'sources': [cython_gen.process('common.pyx')]},
|
||||
}
|
||||
|
||||
foreach ext_name, ext_dict : hist_gradient_boosting_extension_metadata
|
||||
py.extension_module(
|
||||
ext_name,
|
||||
ext_dict.get('sources'),
|
||||
dependencies: ext_dict.get('dependencies', []),
|
||||
subdir: 'sklearn/ensemble/_hist_gradient_boosting',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
|
||||
+1201
-1201
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
py.extension_module(
|
||||
'_gradient_boosting',
|
||||
[cython_gen.process('_gradient_boosting.pyx')] + utils_cython_tree,
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/ensemble',
|
||||
install: true
|
||||
)
|
||||
|
||||
subdir('_hist_gradient_boosting')
|
||||
py.extension_module(
|
||||
'_gradient_boosting',
|
||||
[cython_gen.process('_gradient_boosting.pyx')] + utils_cython_tree,
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/ensemble',
|
||||
install: true
|
||||
)
|
||||
|
||||
subdir('_hist_gradient_boosting')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
This directory contains bundled external dependencies that are updated
|
||||
every once in a while.
|
||||
|
||||
Note for distribution packagers: if you want to remove the duplicated
|
||||
code and depend on a packaged version, we suggest that you simply do a
|
||||
symbolic link in this directory.
|
||||
|
||||
This directory contains bundled external dependencies that are updated
|
||||
every once in a while.
|
||||
|
||||
Note for distribution packagers: if you want to remove the duplicated
|
||||
code and depend on a packaged version, we suggest that you simply do a
|
||||
symbolic link in this directory.
|
||||
|
||||
|
||||
+21
-21
@@ -1,21 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Consortium for Python Data API Standards
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Consortium for Python Data API Standards
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
Update this directory using maint_tools/vendor_array_api_compat.sh
|
||||
Update this directory using maint_tools/vendor_array_api_compat.sh
|
||||
|
||||
+21
-21
@@ -1,21 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Consortium for Python Data API Standards
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Consortium for Python Data API Standards
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
Update this directory using maint_tools/vendor_array_api_extra.sh
|
||||
Update this directory using maint_tools/vendor_array_api_extra.sh
|
||||
|
||||
Vendored
+40
-40
@@ -1,40 +1,40 @@
|
||||
"""Static type stubs for `_compat.py`."""
|
||||
|
||||
# https://github.com/scikit-learn/scikit-learn/pull/27910#issuecomment-2568023972
|
||||
from __future__ import annotations
|
||||
|
||||
from types import ModuleType
|
||||
|
||||
# TODO import from typing (requires Python >=3.13)
|
||||
from typing_extensions import TypeIs
|
||||
|
||||
from ._typing import Array, Device
|
||||
|
||||
# pylint: disable=missing-class-docstring,unused-argument
|
||||
|
||||
class Namespace(ModuleType):
|
||||
def device(self, x: Array, /) -> Device: ...
|
||||
|
||||
def array_namespace(
|
||||
*xs: Array | complex | None,
|
||||
api_version: str | None = None,
|
||||
use_compat: bool | None = None,
|
||||
) -> Namespace: ...
|
||||
def device(x: Array, /) -> Device: ...
|
||||
def is_array_api_obj(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_array_api_strict_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_cupy_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_dask_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_jax_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_numpy_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_pydata_sparse_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_torch_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_cupy_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_dask_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_jax_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_numpy_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_pydata_sparse_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_torch_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_lazy_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_writeable_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def size(x: Array, /) -> int | None: ...
|
||||
"""Static type stubs for `_compat.py`."""
|
||||
|
||||
# https://github.com/scikit-learn/scikit-learn/pull/27910#issuecomment-2568023972
|
||||
from __future__ import annotations
|
||||
|
||||
from types import ModuleType
|
||||
|
||||
# TODO import from typing (requires Python >=3.13)
|
||||
from typing_extensions import TypeIs
|
||||
|
||||
from ._typing import Array, Device
|
||||
|
||||
# pylint: disable=missing-class-docstring,unused-argument
|
||||
|
||||
class Namespace(ModuleType):
|
||||
def device(self, x: Array, /) -> Device: ...
|
||||
|
||||
def array_namespace(
|
||||
*xs: Array | complex | None,
|
||||
api_version: str | None = None,
|
||||
use_compat: bool | None = None,
|
||||
) -> Namespace: ...
|
||||
def device(x: Array, /) -> Device: ...
|
||||
def is_array_api_obj(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_array_api_strict_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_cupy_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_dask_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_jax_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_numpy_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_pydata_sparse_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_torch_namespace(xp: ModuleType, /) -> TypeIs[Namespace]: ...
|
||||
def is_cupy_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_dask_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_jax_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_numpy_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_pydata_sparse_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_torch_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_lazy_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def is_writeable_array(x: object, /) -> TypeIs[Array]: ...
|
||||
def size(x: Array, /) -> int | None: ...
|
||||
|
||||
Vendored
+105
-105
@@ -1,105 +1,105 @@
|
||||
"""Static typing helpers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from types import EllipsisType
|
||||
from typing import Protocol, TypeAlias
|
||||
|
||||
# TODO import from typing (requires Python >=3.12)
|
||||
from typing_extensions import override
|
||||
|
||||
# TODO: use array-api-typing once it is available
|
||||
|
||||
class Array(Protocol): # pylint: disable=missing-class-docstring
|
||||
# Unary operations
|
||||
def __abs__(self) -> Array: ...
|
||||
def __pos__(self) -> Array: ...
|
||||
def __neg__(self) -> Array: ...
|
||||
def __invert__(self) -> Array: ...
|
||||
# Binary operations
|
||||
def __add__(self, other: Array | complex, /) -> Array: ...
|
||||
def __sub__(self, other: Array | complex, /) -> Array: ...
|
||||
def __mul__(self, other: Array | complex, /) -> Array: ...
|
||||
def __truediv__(self, other: Array | complex, /) -> Array: ...
|
||||
def __floordiv__(self, other: Array | complex, /) -> Array: ...
|
||||
def __mod__(self, other: Array | complex, /) -> Array: ...
|
||||
def __pow__(self, other: Array | complex, /) -> Array: ...
|
||||
def __matmul__(self, other: Array, /) -> Array: ...
|
||||
def __and__(self, other: Array | int, /) -> Array: ...
|
||||
def __or__(self, other: Array | int, /) -> Array: ...
|
||||
def __xor__(self, other: Array | int, /) -> Array: ...
|
||||
def __lshift__(self, other: Array | int, /) -> Array: ...
|
||||
def __rshift__(self, other: Array | int, /) -> Array: ...
|
||||
def __lt__(self, other: Array | complex, /) -> Array: ...
|
||||
def __le__(self, other: Array | complex, /) -> Array: ...
|
||||
def __gt__(self, other: Array | complex, /) -> Array: ...
|
||||
def __ge__(self, other: Array | complex, /) -> Array: ...
|
||||
@override
|
||||
def __eq__(self, other: Array | complex, /) -> Array: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
@override
|
||||
def __ne__(self, other: Array | complex, /) -> Array: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
# Reflected operations
|
||||
def __radd__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rsub__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rmul__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rtruediv__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rfloordiv__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rmod__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rpow__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rmatmul__(self, other: Array, /) -> Array: ...
|
||||
def __rand__(self, other: Array | int, /) -> Array: ...
|
||||
def __ror__(self, other: Array | int, /) -> Array: ...
|
||||
def __rxor__(self, other: Array | int, /) -> Array: ...
|
||||
def __rlshift__(self, other: Array | int, /) -> Array: ...
|
||||
def __rrshift__(self, other: Array | int, /) -> Array: ...
|
||||
# Attributes
|
||||
@property
|
||||
def dtype(self) -> DType: ...
|
||||
@property
|
||||
def device(self) -> Device: ...
|
||||
@property
|
||||
def mT(self) -> Array: ... # pylint: disable=invalid-name
|
||||
@property
|
||||
def ndim(self) -> int: ...
|
||||
@property
|
||||
def shape(self) -> tuple[int | None, ...]: ...
|
||||
@property
|
||||
def size(self) -> int | None: ...
|
||||
@property
|
||||
def T(self) -> Array: ... # pylint: disable=invalid-name
|
||||
# Collection operations (note: an Array does not have to be Sized or Iterable)
|
||||
def __getitem__(self, key: GetIndex, /) -> Array: ...
|
||||
def __setitem__(self, key: SetIndex, value: Array | complex, /) -> None: ...
|
||||
# Materialization methods (may raise on lazy arrays)
|
||||
def __bool__(self) -> bool: ...
|
||||
def __complex__(self) -> complex: ...
|
||||
def __float__(self) -> float: ...
|
||||
def __index__(self) -> int: ...
|
||||
def __int__(self) -> int: ...
|
||||
|
||||
# Misc methods (frequently not implemented in Arrays wrapped by array-api-compat)
|
||||
# def __array_namespace__(*, api_version: str | None) -> ModuleType: ...
|
||||
# def __dlpack__(
|
||||
# *,
|
||||
# stream: int | Any | None = None,
|
||||
# max_version: tuple[int, int] | None = None,
|
||||
# dl_device: tuple[int, int] | None = None, # tuple[Enum, int]
|
||||
# copy: bool | None = None,
|
||||
# ) -> Any: ...
|
||||
# def __dlpack_device__() -> tuple[int, int]: ... # tuple[Enum, int]
|
||||
# def to_device(device: Device, /, *, stream: int | Any | None = None) -> Array: ...
|
||||
|
||||
class DType(Protocol): # pylint: disable=missing-class-docstring
|
||||
pass
|
||||
|
||||
class Device(Protocol): # pylint: disable=missing-class-docstring
|
||||
pass
|
||||
|
||||
SetIndex: TypeAlias = ( # type: ignore[explicit-any]
|
||||
int | slice | EllipsisType | Array | tuple[int | slice | EllipsisType | Array, ...]
|
||||
)
|
||||
GetIndex: TypeAlias = ( # type: ignore[explicit-any]
|
||||
SetIndex | None | tuple[int | slice | EllipsisType | None | Array, ...]
|
||||
)
|
||||
|
||||
__all__ = ["Array", "DType", "Device", "GetIndex", "SetIndex"]
|
||||
"""Static typing helpers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from types import EllipsisType
|
||||
from typing import Protocol, TypeAlias
|
||||
|
||||
# TODO import from typing (requires Python >=3.12)
|
||||
from typing_extensions import override
|
||||
|
||||
# TODO: use array-api-typing once it is available
|
||||
|
||||
class Array(Protocol): # pylint: disable=missing-class-docstring
|
||||
# Unary operations
|
||||
def __abs__(self) -> Array: ...
|
||||
def __pos__(self) -> Array: ...
|
||||
def __neg__(self) -> Array: ...
|
||||
def __invert__(self) -> Array: ...
|
||||
# Binary operations
|
||||
def __add__(self, other: Array | complex, /) -> Array: ...
|
||||
def __sub__(self, other: Array | complex, /) -> Array: ...
|
||||
def __mul__(self, other: Array | complex, /) -> Array: ...
|
||||
def __truediv__(self, other: Array | complex, /) -> Array: ...
|
||||
def __floordiv__(self, other: Array | complex, /) -> Array: ...
|
||||
def __mod__(self, other: Array | complex, /) -> Array: ...
|
||||
def __pow__(self, other: Array | complex, /) -> Array: ...
|
||||
def __matmul__(self, other: Array, /) -> Array: ...
|
||||
def __and__(self, other: Array | int, /) -> Array: ...
|
||||
def __or__(self, other: Array | int, /) -> Array: ...
|
||||
def __xor__(self, other: Array | int, /) -> Array: ...
|
||||
def __lshift__(self, other: Array | int, /) -> Array: ...
|
||||
def __rshift__(self, other: Array | int, /) -> Array: ...
|
||||
def __lt__(self, other: Array | complex, /) -> Array: ...
|
||||
def __le__(self, other: Array | complex, /) -> Array: ...
|
||||
def __gt__(self, other: Array | complex, /) -> Array: ...
|
||||
def __ge__(self, other: Array | complex, /) -> Array: ...
|
||||
@override
|
||||
def __eq__(self, other: Array | complex, /) -> Array: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
@override
|
||||
def __ne__(self, other: Array | complex, /) -> Array: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
# Reflected operations
|
||||
def __radd__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rsub__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rmul__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rtruediv__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rfloordiv__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rmod__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rpow__(self, other: Array | complex, /) -> Array: ...
|
||||
def __rmatmul__(self, other: Array, /) -> Array: ...
|
||||
def __rand__(self, other: Array | int, /) -> Array: ...
|
||||
def __ror__(self, other: Array | int, /) -> Array: ...
|
||||
def __rxor__(self, other: Array | int, /) -> Array: ...
|
||||
def __rlshift__(self, other: Array | int, /) -> Array: ...
|
||||
def __rrshift__(self, other: Array | int, /) -> Array: ...
|
||||
# Attributes
|
||||
@property
|
||||
def dtype(self) -> DType: ...
|
||||
@property
|
||||
def device(self) -> Device: ...
|
||||
@property
|
||||
def mT(self) -> Array: ... # pylint: disable=invalid-name
|
||||
@property
|
||||
def ndim(self) -> int: ...
|
||||
@property
|
||||
def shape(self) -> tuple[int | None, ...]: ...
|
||||
@property
|
||||
def size(self) -> int | None: ...
|
||||
@property
|
||||
def T(self) -> Array: ... # pylint: disable=invalid-name
|
||||
# Collection operations (note: an Array does not have to be Sized or Iterable)
|
||||
def __getitem__(self, key: GetIndex, /) -> Array: ...
|
||||
def __setitem__(self, key: SetIndex, value: Array | complex, /) -> None: ...
|
||||
# Materialization methods (may raise on lazy arrays)
|
||||
def __bool__(self) -> bool: ...
|
||||
def __complex__(self) -> complex: ...
|
||||
def __float__(self) -> float: ...
|
||||
def __index__(self) -> int: ...
|
||||
def __int__(self) -> int: ...
|
||||
|
||||
# Misc methods (frequently not implemented in Arrays wrapped by array-api-compat)
|
||||
# def __array_namespace__(*, api_version: str | None) -> ModuleType: ...
|
||||
# def __dlpack__(
|
||||
# *,
|
||||
# stream: int | Any | None = None,
|
||||
# max_version: tuple[int, int] | None = None,
|
||||
# dl_device: tuple[int, int] | None = None, # tuple[Enum, int]
|
||||
# copy: bool | None = None,
|
||||
# ) -> Any: ...
|
||||
# def __dlpack_device__() -> tuple[int, int]: ... # tuple[Enum, int]
|
||||
# def to_device(device: Device, /, *, stream: int | Any | None = None) -> Array: ...
|
||||
|
||||
class DType(Protocol): # pylint: disable=missing-class-docstring
|
||||
pass
|
||||
|
||||
class Device(Protocol): # pylint: disable=missing-class-docstring
|
||||
pass
|
||||
|
||||
SetIndex: TypeAlias = ( # type: ignore[explicit-any]
|
||||
int | slice | EllipsisType | Array | tuple[int | slice | EllipsisType | Array, ...]
|
||||
)
|
||||
GetIndex: TypeAlias = ( # type: ignore[explicit-any]
|
||||
SetIndex | None | tuple[int | slice | EllipsisType | None | Array, ...]
|
||||
)
|
||||
|
||||
__all__ = ["Array", "DType", "Device", "GetIndex", "SetIndex"]
|
||||
|
||||
+89
-89
@@ -1,89 +1,89 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from libc.stdlib cimport abs
|
||||
from libcpp.vector cimport vector
|
||||
|
||||
cimport numpy as cnp
|
||||
import numpy as np
|
||||
from ..utils._typedefs cimport int32_t, int64_t
|
||||
from ..utils.murmurhash cimport murmurhash3_bytes_s32
|
||||
from ..utils._vector_sentinel cimport vector_to_nd_array
|
||||
|
||||
cnp.import_array()
|
||||
|
||||
|
||||
def transform(raw_X, Py_ssize_t n_features, dtype,
|
||||
bint alternate_sign=1, unsigned int seed=0):
|
||||
"""Guts of FeatureHasher.transform.
|
||||
|
||||
Returns
|
||||
-------
|
||||
n_samples : integer
|
||||
indices, indptr, values : lists
|
||||
For constructing a scipy.sparse.csr_matrix.
|
||||
|
||||
"""
|
||||
cdef int32_t h
|
||||
cdef double value
|
||||
|
||||
cdef vector[int32_t] indices
|
||||
cdef vector[int64_t] indptr
|
||||
indptr.push_back(0)
|
||||
|
||||
# Since Python array does not understand Numpy dtypes, we grow the indices
|
||||
# and values arrays ourselves. Use a Py_ssize_t capacity for safety.
|
||||
cdef Py_ssize_t capacity = 8192 # arbitrary
|
||||
cdef int64_t size = 0
|
||||
cdef cnp.ndarray values = np.empty(capacity, dtype=dtype)
|
||||
|
||||
for x in raw_X:
|
||||
for f, v in x:
|
||||
if isinstance(v, (str, unicode)):
|
||||
f = "%s%s%s" % (f, '=', v)
|
||||
value = 1
|
||||
else:
|
||||
value = v
|
||||
|
||||
if value == 0:
|
||||
continue
|
||||
|
||||
if isinstance(f, unicode):
|
||||
f = (<unicode>f).encode("utf-8")
|
||||
# Need explicit type check because Murmurhash does not propagate
|
||||
# all exceptions. Add "except *" there?
|
||||
elif not isinstance(f, bytes):
|
||||
raise TypeError("feature names must be strings")
|
||||
|
||||
h = murmurhash3_bytes_s32(<bytes>f, seed)
|
||||
|
||||
if h == - 2147483648:
|
||||
# abs(-2**31) is undefined behavior because h is a `np.int32`
|
||||
# The following is defined such that it is equal to: abs(-2**31) % n_features
|
||||
indices.push_back((2147483647 - (n_features - 1)) % n_features)
|
||||
else:
|
||||
indices.push_back(abs(h) % n_features)
|
||||
# improve inner product preservation in the hashed space
|
||||
if alternate_sign:
|
||||
value *= (h >= 0) * 2 - 1
|
||||
values[size] = value
|
||||
size += 1
|
||||
|
||||
if size == capacity:
|
||||
capacity *= 2
|
||||
# can't use resize member because there might be multiple
|
||||
# references to the arrays due to Cython's error checking
|
||||
values = np.resize(values, capacity)
|
||||
|
||||
indptr.push_back(size)
|
||||
|
||||
indices_array = vector_to_nd_array(&indices)
|
||||
indptr_array = vector_to_nd_array(&indptr)
|
||||
|
||||
if indptr_array[indptr_array.shape[0]-1] > np.iinfo(np.int32).max: # = 2**31 - 1
|
||||
# both indices and indptr have the same dtype in CSR arrays
|
||||
indices_array = indices_array.astype(np.int64, copy=False)
|
||||
else:
|
||||
indptr_array = indptr_array.astype(np.int32, copy=False)
|
||||
|
||||
return (indices_array, indptr_array, values[:size])
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
from libc.stdlib cimport abs
|
||||
from libcpp.vector cimport vector
|
||||
|
||||
cimport numpy as cnp
|
||||
import numpy as np
|
||||
from ..utils._typedefs cimport int32_t, int64_t
|
||||
from ..utils.murmurhash cimport murmurhash3_bytes_s32
|
||||
from ..utils._vector_sentinel cimport vector_to_nd_array
|
||||
|
||||
cnp.import_array()
|
||||
|
||||
|
||||
def transform(raw_X, Py_ssize_t n_features, dtype,
|
||||
bint alternate_sign=1, unsigned int seed=0):
|
||||
"""Guts of FeatureHasher.transform.
|
||||
|
||||
Returns
|
||||
-------
|
||||
n_samples : integer
|
||||
indices, indptr, values : lists
|
||||
For constructing a scipy.sparse.csr_matrix.
|
||||
|
||||
"""
|
||||
cdef int32_t h
|
||||
cdef double value
|
||||
|
||||
cdef vector[int32_t] indices
|
||||
cdef vector[int64_t] indptr
|
||||
indptr.push_back(0)
|
||||
|
||||
# Since Python array does not understand Numpy dtypes, we grow the indices
|
||||
# and values arrays ourselves. Use a Py_ssize_t capacity for safety.
|
||||
cdef Py_ssize_t capacity = 8192 # arbitrary
|
||||
cdef int64_t size = 0
|
||||
cdef cnp.ndarray values = np.empty(capacity, dtype=dtype)
|
||||
|
||||
for x in raw_X:
|
||||
for f, v in x:
|
||||
if isinstance(v, (str, unicode)):
|
||||
f = "%s%s%s" % (f, '=', v)
|
||||
value = 1
|
||||
else:
|
||||
value = v
|
||||
|
||||
if value == 0:
|
||||
continue
|
||||
|
||||
if isinstance(f, unicode):
|
||||
f = (<unicode>f).encode("utf-8")
|
||||
# Need explicit type check because Murmurhash does not propagate
|
||||
# all exceptions. Add "except *" there?
|
||||
elif not isinstance(f, bytes):
|
||||
raise TypeError("feature names must be strings")
|
||||
|
||||
h = murmurhash3_bytes_s32(<bytes>f, seed)
|
||||
|
||||
if h == - 2147483648:
|
||||
# abs(-2**31) is undefined behavior because h is a `np.int32`
|
||||
# The following is defined such that it is equal to: abs(-2**31) % n_features
|
||||
indices.push_back((2147483647 - (n_features - 1)) % n_features)
|
||||
else:
|
||||
indices.push_back(abs(h) % n_features)
|
||||
# improve inner product preservation in the hashed space
|
||||
if alternate_sign:
|
||||
value *= (h >= 0) * 2 - 1
|
||||
values[size] = value
|
||||
size += 1
|
||||
|
||||
if size == capacity:
|
||||
capacity *= 2
|
||||
# can't use resize member because there might be multiple
|
||||
# references to the arrays due to Cython's error checking
|
||||
values = np.resize(values, capacity)
|
||||
|
||||
indptr.push_back(size)
|
||||
|
||||
indices_array = vector_to_nd_array(&indices)
|
||||
indptr_array = vector_to_nd_array(&indptr)
|
||||
|
||||
if indptr_array[indptr_array.shape[0]-1] > np.iinfo(np.int32).max: # = 2**31 - 1
|
||||
# both indices and indptr have the same dtype in CSR arrays
|
||||
indices_array = indices_array.astype(np.int64, copy=False)
|
||||
else:
|
||||
indptr_array = indptr_array.astype(np.int32, copy=False)
|
||||
|
||||
return (indices_array, indptr_array, values[:size])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
py.extension_module(
|
||||
'_hashing_fast',
|
||||
[cython_gen_cpp.process('_hashing_fast.pyx'), utils_cython_tree],
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/feature_extraction',
|
||||
install: true
|
||||
)
|
||||
py.extension_module(
|
||||
'_hashing_fast',
|
||||
[cython_gen_cpp.process('_hashing_fast.pyx'), utils_cython_tree],
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/feature_extraction',
|
||||
install: true
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user