pandas-dstoolkit 0.15.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dstoolkit/__init__.py +75 -0
- dstoolkit/_messages.py +92 -0
- dstoolkit/cleaning.py +955 -0
- dstoolkit/exploration.py +509 -0
- dstoolkit/monitoring.py +248 -0
- dstoolkit/profiling.py +1403 -0
- dstoolkit/py.typed +0 -0
- dstoolkit/transformers.py +500 -0
- dstoolkit/validation.py +824 -0
- pandas_dstoolkit-0.15.2.dist-info/METADATA +434 -0
- pandas_dstoolkit-0.15.2.dist-info/RECORD +14 -0
- pandas_dstoolkit-0.15.2.dist-info/WHEEL +5 -0
- pandas_dstoolkit-0.15.2.dist-info/licenses/LICENSE +21 -0
- pandas_dstoolkit-0.15.2.dist-info/top_level.txt +1 -0
dstoolkit/__init__.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""dstoolkit: data cleaning and exploratory analysis helpers for pandas.
|
|
2
|
+
|
|
3
|
+
Everything is available from the top level:
|
|
4
|
+
|
|
5
|
+
import dstoolkit as dst
|
|
6
|
+
|
|
7
|
+
df = dst.convert_types(raw) # yes/no text -> True/False, date text -> dates
|
|
8
|
+
df = dst.clean(df, missing={"numeric": "median"})
|
|
9
|
+
dst.show_distribution_profile(df["age"])
|
|
10
|
+
dst.profile(df).save("report.html")
|
|
11
|
+
dst.validate(df, {"age": {"min": 0, "max": 120}})
|
|
12
|
+
|
|
13
|
+
or from its module: `dstoolkit.cleaning`, `dstoolkit.exploration`,
|
|
14
|
+
`dstoolkit.profiling`, `dstoolkit.validation` and `dstoolkit.monitoring`
|
|
15
|
+
(`compare()`: has new data drifted from the training data?). The scikit-learn
|
|
16
|
+
transformers (MissingFiller, OutlierCapper, CategoryEncoder, Scaler, DateFeatures) are in
|
|
17
|
+
`dstoolkit.transformers` and need the optional scikit-learn extra.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from . import cleaning, exploration, monitoring, profiling, validation
|
|
21
|
+
from ._messages import get_message_output, set_message_output
|
|
22
|
+
from .cleaning import (
|
|
23
|
+
add_age_column,
|
|
24
|
+
clean,
|
|
25
|
+
clean_column_names,
|
|
26
|
+
convert_types,
|
|
27
|
+
encode_categorical,
|
|
28
|
+
fill_missing,
|
|
29
|
+
find_outliers,
|
|
30
|
+
handle_outliers,
|
|
31
|
+
log_transform,
|
|
32
|
+
normalize,
|
|
33
|
+
remove_duplicates,
|
|
34
|
+
standardize_labels,
|
|
35
|
+
to_boolean,
|
|
36
|
+
to_category,
|
|
37
|
+
to_datetime_columns,
|
|
38
|
+
winsorize,
|
|
39
|
+
)
|
|
40
|
+
from .exploration import (
|
|
41
|
+
add_passed,
|
|
42
|
+
associations,
|
|
43
|
+
drop_nulls,
|
|
44
|
+
fit_line,
|
|
45
|
+
show_counts,
|
|
46
|
+
show_density,
|
|
47
|
+
show_distribution,
|
|
48
|
+
show_distribution_profile,
|
|
49
|
+
show_eda,
|
|
50
|
+
show_eda_table,
|
|
51
|
+
show_grouped_box,
|
|
52
|
+
show_histogram,
|
|
53
|
+
show_scatter,
|
|
54
|
+
)
|
|
55
|
+
from .monitoring import compare
|
|
56
|
+
from .profiling import ColumnProfile, Profile, Suggestion, TargetProfile, profile
|
|
57
|
+
from .validation import ColumnRule, Comparison, RuleResult, ValidationError, ValidationReport, validate
|
|
58
|
+
|
|
59
|
+
__version__ = "0.15.2"
|
|
60
|
+
|
|
61
|
+
# The transformers need scikit-learn (an optional extra), so they're imported on
|
|
62
|
+
# first use: `dst.Scaler` works when scikit-learn is installed, and `import
|
|
63
|
+
# dstoolkit` never needs it.
|
|
64
|
+
_TRANSFORMERS = ("MissingFiller", "OutlierCapper", "CategoryEncoder", "Scaler", "DateFeatures")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def __getattr__(name: str) -> object:
|
|
68
|
+
if name in _TRANSFORMERS:
|
|
69
|
+
from . import transformers
|
|
70
|
+
return getattr(transformers, name)
|
|
71
|
+
raise AttributeError(f"module 'dstoolkit' has no attribute {name!r}")
|
|
72
|
+
|
|
73
|
+
__all__ = ["cleaning", "exploration", "monitoring", "profiling", "validation", "__version__",
|
|
74
|
+
"set_message_output", "get_message_output",
|
|
75
|
+
*cleaning.__all__, *exploration.__all__, *monitoring.__all__, *profiling.__all__, *validation.__all__]
|
dstoolkit/_messages.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Where dstoolkit's one-line summaries go ("Filled missing values: age (263)", ...).
|
|
2
|
+
|
|
3
|
+
Every message is sent to the standard `logging` logger named "dstoolkit" at
|
|
4
|
+
INFO level. What happens next depends on set_message_output():
|
|
5
|
+
|
|
6
|
+
- "print" (default): the logger writes the message to the screen (standard
|
|
7
|
+
output), exactly like print(), so notebooks and scripts show it.
|
|
8
|
+
- "logging": the logger hands messages to your own logging setup instead, so
|
|
9
|
+
they get your timestamps and format and go wherever your logs go (a file,
|
|
10
|
+
AWS CloudWatch from a Lambda function, ...).
|
|
11
|
+
- "off": nothing is shown anywhere.
|
|
12
|
+
|
|
13
|
+
`verbose=False` on any function still silences that one call.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
import sys
|
|
20
|
+
from typing import Literal
|
|
21
|
+
|
|
22
|
+
MessageOutput = Literal["print", "logging", "off"]
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger("dstoolkit")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _StdoutHandler(logging.Handler):
|
|
28
|
+
"""Writes the bare message to whatever sys.stdout is at that moment.
|
|
29
|
+
|
|
30
|
+
Looking sys.stdout up on every message (rather than once, like
|
|
31
|
+
logging.StreamHandler) keeps Jupyter, pytest's capsys and
|
|
32
|
+
contextlib.redirect_stdout working.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
36
|
+
try:
|
|
37
|
+
sys.stdout.write(self.format(record) + "\n")
|
|
38
|
+
except Exception: # pragma: no cover - logging must never crash the caller
|
|
39
|
+
self.handleError(record)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
_console = _StdoutHandler()
|
|
43
|
+
_output: MessageOutput = "print"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def set_message_output(output: MessageOutput) -> None:
|
|
47
|
+
"""Choose where dstoolkit's summaries go: "print" (default), "logging" or "off".
|
|
48
|
+
|
|
49
|
+
"logging" sends them to the "dstoolkit" logger at INFO level and lets your
|
|
50
|
+
logging configuration handle them, for example:
|
|
51
|
+
|
|
52
|
+
import logging
|
|
53
|
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(name)s %(message)s")
|
|
54
|
+
dst.set_message_output("logging")
|
|
55
|
+
|
|
56
|
+
The setting applies to the whole Python session.
|
|
57
|
+
"""
|
|
58
|
+
global _output
|
|
59
|
+
if output not in ("print", "logging", "off"):
|
|
60
|
+
raise ValueError(f'output must be "print", "logging" or "off", got {output!r}')
|
|
61
|
+
_output = output
|
|
62
|
+
# Remove every copy of the print handler, including one left by an earlier import of
|
|
63
|
+
# this module (importlib.reload or Jupyter's %autoreload), so messages never print twice
|
|
64
|
+
for handler in list(logger.handlers):
|
|
65
|
+
if type(handler).__name__ == "_StdoutHandler":
|
|
66
|
+
logger.removeHandler(handler)
|
|
67
|
+
if output == "print":
|
|
68
|
+
logger.addHandler(_console)
|
|
69
|
+
logger.setLevel(logging.INFO)
|
|
70
|
+
logger.propagate = False # don't also pass it to the app's logging setup
|
|
71
|
+
elif output == "logging":
|
|
72
|
+
logger.setLevel(logging.NOTSET) # the app's logging configuration decides
|
|
73
|
+
logger.propagate = True
|
|
74
|
+
else:
|
|
75
|
+
logger.setLevel(logging.CRITICAL + 1)
|
|
76
|
+
logger.propagate = False
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_message_output() -> MessageOutput:
|
|
80
|
+
"""The current setting of set_message_output()."""
|
|
81
|
+
return _output
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def say(verbose: bool, message: str) -> None:
|
|
85
|
+
"""Send one summary message, unless this call was made with verbose=False."""
|
|
86
|
+
if verbose:
|
|
87
|
+
logger.info(message)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if not any(isinstance(h, logging.NullHandler) for h in logger.handlers):
|
|
91
|
+
logger.addHandler(logging.NullHandler()) # standard library practice for packages
|
|
92
|
+
set_message_output("print")
|