variable-explorer 0.1.0__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.
- variable_explorer/__init__.py +7 -0
- variable_explorer/_version.py +4 -0
- variable_explorer/kernel/__init__.py +5 -0
- variable_explorer/kernel/comm_handler.py +255 -0
- variable_explorer/kernel/data_provider.py +235 -0
- variable_explorer/kernel/editor.py +88 -0
- variable_explorer/kernel/introspection.py +186 -0
- variable_explorer/kernel/serialization.py +73 -0
- variable_explorer/kernel/sorter.py +34 -0
- variable_explorer/kernel/statistics.py +101 -0
- variable_explorer/labextension/build_log.json +726 -0
- variable_explorer/labextension/package.json +96 -0
- variable_explorer/labextension/schemas/variable-explorer/package.json.orig +91 -0
- variable_explorer/labextension/schemas/variable-explorer/plugin.json +75 -0
- variable_explorer/labextension/static/lib_index_js.88a2cd3be0f2bf49f0eb.js +1417 -0
- variable_explorer/labextension/static/lib_index_js.88a2cd3be0f2bf49f0eb.js.map +1 -0
- variable_explorer/labextension/static/remoteEntry.a8ed3dcc7548f0b68f93.js +576 -0
- variable_explorer/labextension/static/remoteEntry.a8ed3dcc7548f0b68f93.js.map +1 -0
- variable_explorer/labextension/static/style.js +4 -0
- variable_explorer/labextension/static/style_index_js-data_font_woff2_charset_utf-8_base64_d09GMgABAAAAABmsAAsAAAAANbQAABlcAAEAAAAAA-5c9677.c69a59632d259bde8f84.js +785 -0
- variable_explorer/labextension/static/style_index_js-data_font_woff2_charset_utf-8_base64_d09GMgABAAAAABmsAAsAAAAANbQAABlcAAEAAAAAA-5c9677.c69a59632d259bde8f84.js.map +1 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-community_dist_package_main_esm_mjs.c38425b170e91e5db052.js +50347 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-community_dist_package_main_esm_mjs.c38425b170e91e5db052.js.map +1 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-community_styles_ag-grid_css-node_modules_ag-grid-community_styl-7d25f0.7424d30423d9f1c112f6.js +8124 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-community_styles_ag-grid_css-node_modules_ag-grid-community_styl-7d25f0.7424d30423d9f1c112f6.js.map +1 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-react_dist_package_index_esm_mjs.ca52d36c364e6562240a.js +2917 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-react_dist_package_index_esm_mjs.ca52d36c364e6562240a.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/build_log.json +726 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/install.json +5 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/package.json +96 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/schemas/variable-explorer/package.json.orig +91 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/schemas/variable-explorer/plugin.json +75 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/lib_index_js.88a2cd3be0f2bf49f0eb.js +1417 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/lib_index_js.88a2cd3be0f2bf49f0eb.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/remoteEntry.a8ed3dcc7548f0b68f93.js +576 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/remoteEntry.a8ed3dcc7548f0b68f93.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/style.js +4 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/style_index_js-data_font_woff2_charset_utf-8_base64_d09GMgABAAAAABmsAAsAAAAANbQAABlcAAEAAAAAA-5c9677.c69a59632d259bde8f84.js +785 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/style_index_js-data_font_woff2_charset_utf-8_base64_d09GMgABAAAAABmsAAsAAAAANbQAABlcAAEAAAAAA-5c9677.c69a59632d259bde8f84.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-community_dist_package_main_esm_mjs.c38425b170e91e5db052.js +50347 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-community_dist_package_main_esm_mjs.c38425b170e91e5db052.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-community_styles_ag-grid_css-node_modules_ag-grid-community_styl-7d25f0.7424d30423d9f1c112f6.js +8124 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-community_styles_ag-grid_css-node_modules_ag-grid-community_styl-7d25f0.7424d30423d9f1c112f6.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-react_dist_package_index_esm_mjs.ca52d36c364e6562240a.js +2917 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-react_dist_package_index_esm_mjs.ca52d36c364e6562240a.js.map +1 -0
- variable_explorer-0.1.0.dist-info/METADATA +80 -0
- variable_explorer-0.1.0.dist-info/RECORD +49 -0
- variable_explorer-0.1.0.dist-info/WHEEL +4 -0
- variable_explorer-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Namespace introspection — scan user variables and extract metadata."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
# Types/modules to skip
|
|
9
|
+
_SKIP_TYPES = (type, type(sys), type(lambda: None))
|
|
10
|
+
_SKIP_PREFIXES = ('_', '__')
|
|
11
|
+
_SKIP_NAMES = {
|
|
12
|
+
'In', 'Out', 'get_ipython', 'exit', 'quit',
|
|
13
|
+
'_dh', '_ih', '_oh', '_sh', '_i', '_ii', '_iii',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_variable_list(user_ns: dict) -> list[dict]:
|
|
18
|
+
"""Scan the user namespace and return metadata for each variable."""
|
|
19
|
+
variables = []
|
|
20
|
+
|
|
21
|
+
for name, obj in user_ns.items():
|
|
22
|
+
if name in _SKIP_NAMES:
|
|
23
|
+
continue
|
|
24
|
+
if any(name.startswith(p) for p in _SKIP_PREFIXES):
|
|
25
|
+
continue
|
|
26
|
+
if isinstance(obj, _SKIP_TYPES):
|
|
27
|
+
continue
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
info = _inspect_variable(name, obj)
|
|
31
|
+
if info is not None:
|
|
32
|
+
variables.append(info)
|
|
33
|
+
except Exception:
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
return variables
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _inspect_variable(name: str, obj: Any) -> dict | None:
|
|
40
|
+
"""Extract metadata for a single variable."""
|
|
41
|
+
type_name = type(obj).__name__
|
|
42
|
+
shape = _get_shape(obj)
|
|
43
|
+
memory_bytes = _get_memory(obj)
|
|
44
|
+
short_repr = _get_short_repr(obj)
|
|
45
|
+
tabular_info = _classify_tabular(obj)
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
'name': name,
|
|
49
|
+
'typeName': type_name,
|
|
50
|
+
'shape': shape,
|
|
51
|
+
'memoryBytes': memory_bytes,
|
|
52
|
+
'shortRepr': short_repr,
|
|
53
|
+
'isTabular': tabular_info['isTabular'],
|
|
54
|
+
'tabularKind': tabular_info['kind'],
|
|
55
|
+
'childCount': tabular_info.get('childCount', 0),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _classify_tabular(obj: Any) -> dict:
|
|
60
|
+
"""Classify what kind of tabular display an object supports."""
|
|
61
|
+
try:
|
|
62
|
+
import pandas as pd
|
|
63
|
+
if isinstance(obj, pd.DataFrame):
|
|
64
|
+
return {'isTabular': True, 'kind': 'dataframe'}
|
|
65
|
+
if isinstance(obj, pd.Series):
|
|
66
|
+
return {'isTabular': True, 'kind': 'series'}
|
|
67
|
+
except ImportError:
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
import numpy as np
|
|
72
|
+
if isinstance(obj, np.ndarray) and obj.ndim <= 2:
|
|
73
|
+
return {'isTabular': True, 'kind': 'ndarray'}
|
|
74
|
+
except ImportError:
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
if isinstance(obj, dict):
|
|
78
|
+
values = list(obj.values())
|
|
79
|
+
if not values:
|
|
80
|
+
return {'isTabular': False, 'kind': 'dict_empty'}
|
|
81
|
+
|
|
82
|
+
# Dict of lists → tabular
|
|
83
|
+
if all(isinstance(v, (list, tuple)) for v in values):
|
|
84
|
+
return {'isTabular': True, 'kind': 'dict_of_lists'}
|
|
85
|
+
|
|
86
|
+
# Dict of DataFrames → container
|
|
87
|
+
try:
|
|
88
|
+
import pandas as pd
|
|
89
|
+
if all(isinstance(v, pd.DataFrame) for v in values):
|
|
90
|
+
return {'isTabular': True, 'kind': 'dict_of_dataframes', 'childCount': len(values)}
|
|
91
|
+
except ImportError:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
# Dict of dicts → try to convert to DataFrame
|
|
95
|
+
if all(isinstance(v, dict) for v in values):
|
|
96
|
+
return {'isTabular': True, 'kind': 'dict_of_dicts'}
|
|
97
|
+
|
|
98
|
+
# Generic dict with scalar values → single-row tabular
|
|
99
|
+
return {'isTabular': True, 'kind': 'dict_scalar'}
|
|
100
|
+
|
|
101
|
+
if isinstance(obj, (list, tuple)):
|
|
102
|
+
if not obj:
|
|
103
|
+
return {'isTabular': False, 'kind': 'list_empty'}
|
|
104
|
+
|
|
105
|
+
# List of DataFrames → container
|
|
106
|
+
try:
|
|
107
|
+
import pandas as pd
|
|
108
|
+
if all(isinstance(v, pd.DataFrame) for v in obj):
|
|
109
|
+
return {'isTabular': True, 'kind': 'list_of_dataframes', 'childCount': len(obj)}
|
|
110
|
+
except ImportError:
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
# List of dicts → tabular (common pattern from APIs/JSON)
|
|
114
|
+
if all(isinstance(v, dict) for v in obj):
|
|
115
|
+
return {'isTabular': True, 'kind': 'list_of_dicts'}
|
|
116
|
+
|
|
117
|
+
# List of lists/tuples → tabular
|
|
118
|
+
if all(isinstance(v, (list, tuple)) for v in obj):
|
|
119
|
+
return {'isTabular': True, 'kind': 'list_of_lists'}
|
|
120
|
+
|
|
121
|
+
# Simple list of scalars → single-column tabular
|
|
122
|
+
return {'isTabular': True, 'kind': 'list_scalar'}
|
|
123
|
+
|
|
124
|
+
return {'isTabular': False, 'kind': 'other'}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _get_shape(obj: Any) -> list[int]:
|
|
128
|
+
"""Get the shape of an object."""
|
|
129
|
+
try:
|
|
130
|
+
import pandas as pd
|
|
131
|
+
if isinstance(obj, pd.DataFrame):
|
|
132
|
+
return list(obj.shape)
|
|
133
|
+
if isinstance(obj, pd.Series):
|
|
134
|
+
return [len(obj)]
|
|
135
|
+
except ImportError:
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
import numpy as np
|
|
140
|
+
if isinstance(obj, np.ndarray):
|
|
141
|
+
return list(obj.shape)
|
|
142
|
+
except ImportError:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
if hasattr(obj, '__len__'):
|
|
146
|
+
try:
|
|
147
|
+
return [len(obj)]
|
|
148
|
+
except Exception:
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
return []
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _get_memory(obj: Any) -> int:
|
|
155
|
+
"""Get memory usage in bytes."""
|
|
156
|
+
try:
|
|
157
|
+
import pandas as pd
|
|
158
|
+
if isinstance(obj, pd.DataFrame):
|
|
159
|
+
return int(obj.memory_usage(deep=True).sum())
|
|
160
|
+
if isinstance(obj, pd.Series):
|
|
161
|
+
return int(obj.memory_usage(deep=True))
|
|
162
|
+
except (ImportError, Exception):
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
import numpy as np
|
|
167
|
+
if isinstance(obj, np.ndarray):
|
|
168
|
+
return int(obj.nbytes)
|
|
169
|
+
except (ImportError, Exception):
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
return sys.getsizeof(obj)
|
|
174
|
+
except Exception:
|
|
175
|
+
return 0
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _get_short_repr(obj: Any, max_len: int = 200) -> str:
|
|
179
|
+
"""Get a short string representation."""
|
|
180
|
+
try:
|
|
181
|
+
r = repr(obj)
|
|
182
|
+
if len(r) > max_len:
|
|
183
|
+
return r[:max_len] + '...'
|
|
184
|
+
return r
|
|
185
|
+
except Exception:
|
|
186
|
+
return f'<{type(obj).__name__}>'
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""JSON-safe serialization for comm messages."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def safe_serialize(data: Any) -> Any:
|
|
9
|
+
"""Recursively convert data to JSON-safe types."""
|
|
10
|
+
if data is None:
|
|
11
|
+
return None
|
|
12
|
+
|
|
13
|
+
if isinstance(data, dict):
|
|
14
|
+
return {str(k): safe_serialize(v) for k, v in data.items()}
|
|
15
|
+
|
|
16
|
+
if isinstance(data, (list, tuple)):
|
|
17
|
+
return [safe_serialize(item) for item in data]
|
|
18
|
+
|
|
19
|
+
if isinstance(data, bool):
|
|
20
|
+
return data
|
|
21
|
+
|
|
22
|
+
if isinstance(data, int):
|
|
23
|
+
return data
|
|
24
|
+
|
|
25
|
+
if isinstance(data, float):
|
|
26
|
+
import math
|
|
27
|
+
if math.isnan(data) or math.isinf(data):
|
|
28
|
+
return None
|
|
29
|
+
return data
|
|
30
|
+
|
|
31
|
+
if isinstance(data, str):
|
|
32
|
+
return data
|
|
33
|
+
|
|
34
|
+
# numpy types
|
|
35
|
+
try:
|
|
36
|
+
import numpy as np
|
|
37
|
+
if isinstance(data, np.integer):
|
|
38
|
+
return int(data)
|
|
39
|
+
if isinstance(data, np.floating):
|
|
40
|
+
v = float(data)
|
|
41
|
+
if np.isnan(v) or np.isinf(v):
|
|
42
|
+
return None
|
|
43
|
+
return v
|
|
44
|
+
if isinstance(data, np.bool_):
|
|
45
|
+
return bool(data)
|
|
46
|
+
if isinstance(data, np.ndarray):
|
|
47
|
+
return data.tolist()
|
|
48
|
+
except ImportError:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
# pandas types
|
|
52
|
+
try:
|
|
53
|
+
import pandas as pd
|
|
54
|
+
if isinstance(data, pd.Timestamp):
|
|
55
|
+
return data.isoformat()
|
|
56
|
+
if pd.isna(data):
|
|
57
|
+
return None
|
|
58
|
+
except (ImportError, TypeError, ValueError):
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
# datetime
|
|
62
|
+
if hasattr(data, 'isoformat'):
|
|
63
|
+
return data.isoformat()
|
|
64
|
+
|
|
65
|
+
# bytes
|
|
66
|
+
if isinstance(data, bytes):
|
|
67
|
+
return data.decode('utf-8', errors='replace')
|
|
68
|
+
|
|
69
|
+
# Fallback
|
|
70
|
+
try:
|
|
71
|
+
return str(data)
|
|
72
|
+
except Exception:
|
|
73
|
+
return '<unserializable>'
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Kernel-side DataFrame sorting."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def apply_sort(df: Any, sort_model: list[dict]) -> Any:
|
|
9
|
+
"""Apply multi-column sort to a DataFrame.
|
|
10
|
+
|
|
11
|
+
sort_model: [{'colId': 'price', 'sort': 'asc'}, ...]
|
|
12
|
+
Returns a new sorted DataFrame (does not modify the original).
|
|
13
|
+
"""
|
|
14
|
+
if not sort_model:
|
|
15
|
+
return df
|
|
16
|
+
|
|
17
|
+
cols = [s['colId'] for s in sort_model]
|
|
18
|
+
ascending = [s['sort'] == 'asc' for s in sort_model]
|
|
19
|
+
|
|
20
|
+
# Validate columns exist
|
|
21
|
+
valid_cols = []
|
|
22
|
+
valid_asc = []
|
|
23
|
+
for col, asc in zip(cols, ascending):
|
|
24
|
+
if col in df.columns:
|
|
25
|
+
valid_cols.append(col)
|
|
26
|
+
valid_asc.append(asc)
|
|
27
|
+
|
|
28
|
+
if not valid_cols:
|
|
29
|
+
return df
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
return df.sort_values(by=valid_cols, ascending=valid_asc, na_position='last')
|
|
33
|
+
except Exception:
|
|
34
|
+
return df
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Column statistics and histogram computation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute_column_stats(var_name: str, obj: Any) -> dict:
|
|
9
|
+
"""Compute statistics for all columns of a DataFrame-like object."""
|
|
10
|
+
import pandas as pd
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
# Convert to DataFrame
|
|
14
|
+
if isinstance(obj, pd.Series):
|
|
15
|
+
df = obj.to_frame()
|
|
16
|
+
elif isinstance(obj, pd.DataFrame):
|
|
17
|
+
df = obj
|
|
18
|
+
else:
|
|
19
|
+
try:
|
|
20
|
+
df = pd.DataFrame(obj)
|
|
21
|
+
except Exception:
|
|
22
|
+
return {
|
|
23
|
+
'type': 'column_stats',
|
|
24
|
+
'variable': var_name,
|
|
25
|
+
'stats': []
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
stats = []
|
|
29
|
+
for col in df.columns:
|
|
30
|
+
series = df[col]
|
|
31
|
+
info: dict[str, Any] = {
|
|
32
|
+
'name': str(col),
|
|
33
|
+
'dtype': str(series.dtype),
|
|
34
|
+
'nullCount': int(series.isna().sum()),
|
|
35
|
+
'uniqueCount': int(series.nunique()),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
info['histogram'] = _compute_histogram(series)
|
|
40
|
+
except Exception:
|
|
41
|
+
info['histogram'] = None
|
|
42
|
+
|
|
43
|
+
stats.append(info)
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
'type': 'column_stats',
|
|
47
|
+
'variable': var_name,
|
|
48
|
+
'stats': stats,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _compute_histogram(series) -> dict | None:
|
|
53
|
+
"""Compute histogram data for a single column."""
|
|
54
|
+
import pandas as pd
|
|
55
|
+
import numpy as np
|
|
56
|
+
|
|
57
|
+
dtype = series.dtype
|
|
58
|
+
|
|
59
|
+
# Boolean
|
|
60
|
+
if pd.api.types.is_bool_dtype(dtype):
|
|
61
|
+
return {
|
|
62
|
+
'type': 'boolean',
|
|
63
|
+
'trueCount': int(series.sum()),
|
|
64
|
+
'falseCount': int((~series).sum()),
|
|
65
|
+
'nullCount': int(series.isna().sum()),
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Numeric (not bool)
|
|
69
|
+
if pd.api.types.is_numeric_dtype(dtype):
|
|
70
|
+
clean = series.dropna()
|
|
71
|
+
if len(clean) == 0:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
# Compute histogram bins
|
|
75
|
+
n_bins = min(20, max(5, len(clean) // 10))
|
|
76
|
+
try:
|
|
77
|
+
counts, edges = np.histogram(clean, bins=n_bins)
|
|
78
|
+
return {
|
|
79
|
+
'type': 'numeric',
|
|
80
|
+
'counts': counts.tolist(),
|
|
81
|
+
'edges': edges.tolist(),
|
|
82
|
+
'min': float(clean.min()),
|
|
83
|
+
'max': float(clean.max()),
|
|
84
|
+
'mean': float(clean.mean()),
|
|
85
|
+
'std': float(clean.std()),
|
|
86
|
+
}
|
|
87
|
+
except Exception:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
# Categorical / object / string
|
|
91
|
+
if pd.api.types.is_categorical_dtype(dtype) or dtype == object or pd.api.types.is_string_dtype(dtype):
|
|
92
|
+
vc = series.value_counts().head(10)
|
|
93
|
+
if len(vc) == 0:
|
|
94
|
+
return None
|
|
95
|
+
return {
|
|
96
|
+
'type': 'categorical',
|
|
97
|
+
'labels': [str(label) for label in vc.index.tolist()],
|
|
98
|
+
'counts': vc.values.tolist(),
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return None
|