Skip to content

Commit 97ed13f

Browse files
committed
added code and license
1 parent 6ea9df5 commit 97ed13f

9 files changed

Lines changed: 2578 additions & 0 deletions

File tree

‎LICENSE‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
MIT License
2+
3+
Copyright (c) 2018-2022, Shaked Zychlinski
4+
All rights reserved.
5+
6+
Permission is hereby granted, free of charge, to any person obtaining
7+
a copy of this software and associated documentation files (the
8+
"Software"), to deal in the Software without restriction, including
9+
without limitation the rights to use, copy, modify, merge, publish,
10+
distribute, sublicense, and/or sell copies of the Software, and to
11+
permit persons to whom the Software is furnished to do so, subject to
12+
the following conditions:
13+
14+
The above copyright notice and this permission notice shall be
15+
included in all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

‎code_0.7.10/dython/__init__.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from . import nominal, model_utils, sampling, data_utils
2+
from ._private import set_is_jupyter
3+
4+
5+
def _get_version_from_setuptools():
6+
from pkg_resources import get_distribution
7+
8+
return get_distribution("dython").version
9+
10+
11+
__all__ = ["__version__"]
12+
__version__ = _get_version_from_setuptools()
13+
set_is_jupyter()

‎code_0.7.10/dython/_private.py‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import sys
2+
import numpy as np
3+
import pandas as pd
4+
import matplotlib.pyplot as plt
5+
from numpy.typing import NDArray
6+
from typing import Optional, Any, Tuple, Union, List, Literal
7+
from .typing import Number, OneDimArray
8+
9+
10+
IS_JUPYTER: bool = False
11+
12+
13+
def set_is_jupyter(force_to: Optional[bool] = None) -> None:
14+
global IS_JUPYTER
15+
if force_to is not None:
16+
IS_JUPYTER = force_to
17+
else:
18+
IS_JUPYTER = "ipykernel_launcher.py" in sys.argv[0]
19+
20+
21+
def plot_or_not(plot: bool) -> None:
22+
if plot:
23+
plt.show()
24+
elif not plot and IS_JUPYTER:
25+
fig = plt.gcf()
26+
if fig:
27+
plt.close(fig)
28+
29+
30+
def convert(
31+
data: Union[List[Number], NDArray, pd.DataFrame],
32+
to: Literal["array", "list", "dataframe"],
33+
copy: bool = True,
34+
) -> Union[List[Number], NDArray, pd.DataFrame]:
35+
converted = None
36+
if to == "array":
37+
if isinstance(data, np.ndarray):
38+
converted = data.copy() if copy else data
39+
elif isinstance(data, pd.Series):
40+
converted = data.values
41+
elif isinstance(data, list):
42+
converted = np.array(data)
43+
elif isinstance(data, pd.DataFrame):
44+
converted = data.values() # type: ignore
45+
elif to == "list":
46+
if isinstance(data, list):
47+
converted = data.copy() if copy else data
48+
elif isinstance(data, pd.Series):
49+
converted = data.values.tolist()
50+
elif isinstance(data, np.ndarray):
51+
converted = data.tolist()
52+
elif to == "dataframe":
53+
if isinstance(data, pd.DataFrame):
54+
converted = data.copy(deep=True) if copy else data
55+
elif isinstance(data, np.ndarray):
56+
converted = pd.DataFrame(data)
57+
else:
58+
raise ValueError("Unknown data conversion: {}".format(to))
59+
if converted is None:
60+
raise TypeError(
61+
"cannot handle data conversion of type: {} to {}".format(
62+
type(data), to
63+
)
64+
)
65+
else:
66+
return converted # type: ignore
67+
68+
69+
def remove_incomplete_samples(
70+
x: Union[List[Any], OneDimArray], y: Union[List[Any], OneDimArray]
71+
) -> Tuple[Union[List[Any], OneDimArray], Union[List[Any], OneDimArray]]:
72+
x = [v if v is not None else np.nan for v in x]
73+
y = [v if v is not None else np.nan for v in y]
74+
arr = np.array([x, y]).transpose()
75+
arr = arr[~np.isnan(arr).any(axis=1)].transpose()
76+
if isinstance(x, list):
77+
return arr[0].tolist(), arr[1].tolist()
78+
else:
79+
return arr[0], arr[1]
80+
81+
82+
def replace_nan_with_value(
83+
x: Union[List[Any], OneDimArray],
84+
y: Union[List[Any], OneDimArray],
85+
value: Any,
86+
) -> Tuple[NDArray, NDArray]:
87+
x = np.array(
88+
[v if v == v and v is not None else value for v in x]
89+
) # NaN != NaN
90+
y = np.array([v if v == v and v is not None else value for v in y])
91+
return x, y

‎code_0.7.10/dython/data_utils.py‎

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import numpy as np
2+
import pandas as pd
3+
import matplotlib.pyplot as plt
4+
from typing import Optional, Tuple, List, Any, Union
5+
from numpy.typing import NDArray
6+
from .typing import Number, TwoDimArray
7+
from ._private import convert, plot_or_not
8+
9+
10+
__all__ = [
11+
"identify_columns_by_type",
12+
"identify_columns_with_na",
13+
"one_hot_encode",
14+
"split_hist",
15+
]
16+
17+
18+
def one_hot_encode(
19+
array: Union[List[Union[Number, str]], NDArray],
20+
classes: Optional[int] = None,
21+
) -> NDArray:
22+
"""
23+
One-hot encode a 1D array.
24+
Based on this StackOverflow answer: https://stackoverflow.com/a/29831596/5863503
25+
26+
Parameters:
27+
-----------
28+
arr : array-like
29+
An array to be one-hot encoded. Must contain only non-negative integers
30+
classes : int or None
31+
number of classes. if None, max value of the array will be used
32+
33+
Returns:
34+
--------
35+
2D one-hot encoded array
36+
37+
Example:
38+
--------
39+
>>> one_hot_encode([1,0,5])
40+
array([[0., 1., 0., 0., 0., 0.],
41+
[1., 0., 0., 0., 0., 0.],
42+
[0., 0., 0., 0., 0., 1.]])
43+
"""
44+
arr: NDArray = convert(array, "array").astype(int) # type: ignore
45+
if not len(arr.shape) == 1:
46+
raise ValueError(
47+
f"array must have only one dimension, but has shape: {arr.shape}"
48+
)
49+
if arr.min() < 0:
50+
raise ValueError("array cannot contain negative values")
51+
classes = classes if classes is not None else arr.max() + 1
52+
h = np.zeros((arr.size, classes)) # type: ignore
53+
h[np.arange(arr.size), arr] = 1
54+
return h
55+
56+
57+
def split_hist(
58+
dataset: pd.DataFrame,
59+
values: str,
60+
split_by: str,
61+
title: Optional[str] = "",
62+
xlabel: Optional[str] = "",
63+
ylabel: Optional[str] = None,
64+
figsize: Optional[Tuple[int, int]] = None,
65+
legend: Optional[str] = "best",
66+
plot: bool = True,
67+
**hist_kwargs,
68+
) -> plt.Axes:
69+
"""
70+
Plot a histogram of values from a given dataset, split by the values of a chosen column
71+
72+
Parameters:
73+
-----------
74+
dataset : Pandas DataFrame
75+
values : string
76+
The column name of the values to be displayed in the histogram
77+
split_by : string
78+
The column name of the values to split the histogram by
79+
title : string or None, default = ''
80+
The plot's title. If empty string, will be '{values} by {split_by}'
81+
xlabel: string or None, default = ''
82+
x-axis label. If empty string, will be '{values}'
83+
ylabel: string or None, default: None
84+
y-axis label
85+
figsize: (int,int) or None, default = None
86+
A Matplotlib figure-size tuple. If `None`, falls back to Matplotlib's
87+
default.
88+
legend: string or None, default = 'best'
89+
A Matplotlib legend location string. See Matplotlib documentation for possible options
90+
plot: Boolean, default = True
91+
Plot the histogram
92+
hist_kwargs: key-value pairs
93+
A key-value pairs to be passed to Matplotlib hist method. See Matplotlib documentation for possible options
94+
95+
Returns:
96+
--------
97+
A Matplotlib `Axes`
98+
99+
Example:
100+
--------
101+
See example under `dython.examples`
102+
"""
103+
plt.figure(figsize=figsize)
104+
split_vals = dataset[split_by].unique()
105+
data_split = list()
106+
for val in split_vals:
107+
data_split.append(dataset[dataset[split_by] == val][values])
108+
hist_kwargs["label"] = split_vals
109+
plt.hist(data_split, **hist_kwargs)
110+
if legend:
111+
plt.legend(loc=legend)
112+
if xlabel is not None:
113+
if xlabel == "":
114+
xlabel = values
115+
plt.xlabel(xlabel)
116+
if title is not None:
117+
if title == "":
118+
title = values + " by " + split_by
119+
plt.title(title)
120+
if ylabel:
121+
plt.ylabel(ylabel)
122+
ax = plt.gca()
123+
plot_or_not(plot)
124+
return ax
125+
126+
127+
def identify_columns_by_type(
128+
dataset: TwoDimArray, include: List[str]
129+
) -> List[Any]:
130+
"""
131+
Given a dataset, identify columns of the types requested.
132+
133+
Parameters:
134+
-----------
135+
dataset : NumPy ndarray / Pandas DataFrame
136+
include : list of strings
137+
Desired column types
138+
139+
Returns:
140+
--------
141+
A list of columns names
142+
143+
Example:
144+
--------
145+
>>> df = pd.DataFrame({'col1': ['a', 'b', 'c', 'a'], 'col2': [3, 4, 2, 1], 'col3': [1., 2., 3., 4.]})
146+
>>> identify_columns_by_type(df, include=['int64', 'float64'])
147+
['col2', 'col3']
148+
149+
"""
150+
df: pd.DataFrame = convert(dataset, "dataframe") # type: ignore
151+
columns = list(df.select_dtypes(include=include).columns)
152+
return columns
153+
154+
155+
def identify_columns_with_na(dataset: TwoDimArray) -> pd.DataFrame:
156+
"""
157+
Return columns names having NA values, sorted in descending order by their number of NAs
158+
159+
Parameters:
160+
-----------
161+
dataset : NumPy ndarray / Pandas DataFrame
162+
163+
Returns:
164+
--------
165+
A DataFrame of two columns (['column', 'na_count']), consisting of only the names
166+
of columns with NA values, sorted by their number of NA values.
167+
168+
Example:
169+
--------
170+
>>> df = pd.DataFrame({'col1': ['a', np.nan, 'a', 'a'], 'col2': [3, np.nan, 2, np.nan], 'col3': [1., 2., 3., 4.]})
171+
>>> identify_columns_with_na(df)
172+
column na_count
173+
1 col2 2
174+
0 col1 1
175+
"""
176+
df: pd.DataFrame = convert(dataset, "dataframe") # type: ignore
177+
na_count = [sum(df[cc].isnull()) for cc in df.columns]
178+
return (
179+
pd.DataFrame({"column": df.columns, "na_count": na_count})
180+
.query("na_count > 0")
181+
.sort_values("na_count", ascending=False)
182+
)

0 commit comments

Comments
 (0)