Skip to content

Commit 9c0ddc9

Browse files
committed
support for Series, list and ndarray -> return float or dict
1 parent ae29059 commit 9c0ddc9

5 files changed

Lines changed: 103 additions & 111 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ Unless noted, IGLU-R test compatability is considered successful if it achieves
4444
| gri |Glycemia Risk Index || ✅ returns float |
4545
| gvp |Glucose Variability Percentage| ✅ | ✅ only Series(DatetimeIndex) returns float
4646
| hbgi |High Blood Glucose Index|| ✅ returns float |
47-
| hyper_index |Hyperglycemia Index||
47+
| hyper_index |Hyperglycemia Index||✅ returns float |
48+
| hyper_index |Hyperglycemia Index||✅ returns float |
4849
| hypo_index |Hypoglycemia Index||
4950
| igc |Index of Glycemic Control||
5051
| in_range_percent |percentage of values within target ranges| ✅ | ✅ returns dict

iglu_python/hyper_index.py

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88

99
def hyper_index(
10-
data: Union[pd.DataFrame, pd.Series], ULTR: int = 140, a: float = 1.1, c: int = 30
11-
) -> pd.DataFrame:
10+
data: Union[pd.DataFrame, pd.Series, np.ndarray, list], ULTR: int = 140, a: float = 1.1, c: int = 30
11+
) -> pd.DataFrame|float:
1212
"""
1313
Calculate Hyperglycemia Index.
1414
@@ -19,8 +19,8 @@ def hyper_index(
1919
2020
Parameters
2121
----------
22-
data : Union[pd.DataFrame, pd.Series]
23-
DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values
22+
data : Union[pd.DataFrame, pd.Series, np.ndarray, list]
23+
DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values
2424
ULTR : int, default=140
2525
Upper Limit of Target Range, in mg/dL
2626
a : float, default=1.1
@@ -31,10 +31,10 @@ def hyper_index(
3131
3232
Returns
3333
-------
34-
pd.DataFrame
34+
pd.DataFrame|float
3535
DataFrame with 1 row for each subject, a column for subject id and a column
3636
for the Hyperglycemia Index value. If a Series of glucose values is passed,
37-
then a DataFrame without the subject id is returned.
37+
then a float is returned.
3838
3939
References
4040
----------
@@ -62,50 +62,32 @@ def hyper_index(
6262
0 0.106
6363
"""
6464
# Handle Series input
65-
is_vector = False
66-
if isinstance(data, (list, np.ndarray)):
67-
data = pd.Series(data)
68-
if isinstance(data, pd.Series):
69-
is_vector = True
70-
data = data.dropna()
71-
if len(data) == 0:
72-
return pd.DataFrame({"GVP": [np.nan]})
73-
74-
# Convert to DataFrame format for processing
75-
data = pd.DataFrame(
76-
{
77-
"id": ["subject1"] * len(data),
78-
"time": pd.date_range(
79-
start="2020-01-01", periods=len(data), freq="5min"
80-
),
81-
"gl": data.values,
82-
}
83-
)
65+
if isinstance(data, (pd.Series,list, np.ndarray)):
66+
if isinstance(data, (np.ndarray, list)):
67+
data = pd.Series(data)
68+
return hyper_index_single(data, ULTR, a, c)
8469

8570
# Check and prepare data
8671
data = check_data_columns(data)
8772

8873
# Calculate hyper_index for each subject
89-
result = []
90-
for subject in data["id"].unique():
91-
subject_data = data[data["id"] == subject]
92-
# Remove NA values
93-
subject_data = subject_data.dropna(subset=["gl"])
94-
95-
if len(subject_data) == 0:
96-
continue
97-
98-
# Calculate hyper_index
99-
hyper_values = subject_data[subject_data["gl"] > ULTR]["gl"] - ULTR
100-
hyper_index = np.sum(hyper_values**a) / (len(subject_data) * c)
101-
102-
result.append({"id": subject, "hyper_index": hyper_index})
103-
104-
# Convert to DataFrame
105-
out = pd.DataFrame(result)
106-
107-
# Remove id column if input was a Series
108-
if is_vector and not out.empty:
109-
out = out.drop("id", axis=1)
74+
out = data.groupby('id').agg(
75+
hyper_index = ("gl", lambda x: hyper_index_single(x, ULTR, a, c))
76+
).reset_index()
11077

11178
return out
79+
80+
def hyper_index_single(
81+
gl: pd.Series, ULTR: int = 140, a: float = 1.1, c: int = 30
82+
) -> float:
83+
"""
84+
Calculate Hyperglycemia Index for a single subject.
85+
"""
86+
gl = gl.dropna()
87+
if len(gl) == 0:
88+
return np.nan
89+
# Calculate hyper_index
90+
hyper_values = gl[gl > ULTR] - ULTR
91+
hyper_index = np.sum(hyper_values**a) / (len(gl) * c)
92+
93+
return hyper_index

iglu_python/hypo_index.py

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88

99
def hypo_index(
10-
data: Union[pd.DataFrame, pd.Series], LLTR: int = 80, b: float = 2, d: int = 30
11-
) -> pd.DataFrame:
10+
data: Union[pd.DataFrame, pd.Series, np.ndarray, list], LLTR: int = 80, b: float = 2, d: int = 30
11+
) -> pd.DataFrame|float:
1212
"""
1313
Calculate Hypoglycemia Index.
1414
@@ -19,8 +19,9 @@ def hypo_index(
1919
2020
Parameters
2121
----------
22-
data : Union[pd.DataFrame, pd.Series]
23-
DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values
22+
data : Union[pd.DataFrame, pd.Series, np.ndarray, list]
23+
DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values,
24+
or a numpy array or list of glucose values
2425
LLTR : int, default=80
2526
Lower Limit of Target Range, in mg/dL
2627
b : float, default=2
@@ -31,10 +32,10 @@ def hypo_index(
3132
3233
Returns
3334
-------
34-
pd.DataFrame
35+
pd.DataFrame|float
3536
DataFrame with 1 row for each subject, a column for subject id and a column
3637
for the Hypoglycemia Index value. If a Series of glucose values is passed,
37-
then a DataFrame without the subject id is returned.
38+
then a float is returned.
3839
3940
References
4041
----------
@@ -62,50 +63,27 @@ def hypo_index(
6263
0 0.106
6364
"""
6465
# Handle Series input
65-
is_vector = False
66-
if isinstance(data, (list, np.ndarray)):
67-
data = pd.Series(data)
68-
if isinstance(data, pd.Series):
69-
is_vector = True
70-
data = data.dropna()
71-
if len(data) == 0:
72-
return pd.DataFrame({"GVP": [np.nan]})
73-
74-
# Convert to DataFrame format for processing
75-
data = pd.DataFrame(
76-
{
77-
"id": ["subject1"] * len(data),
78-
"time": pd.date_range(
79-
start="2020-01-01", periods=len(data), freq="5min"
80-
),
81-
"gl": data.values,
82-
}
83-
)
84-
85-
# Check and prepare data
66+
if isinstance(data, (pd.Series,list, np.ndarray)):
67+
if isinstance(data, (np.ndarray, list)):
68+
data = pd.Series(data)
69+
return hypo_index_single(data, LLTR, b, d)
70+
8671
data = check_data_columns(data)
87-
88-
# Calculate hypo_index for each subject
89-
result = []
90-
for subject in data["id"].unique():
91-
subject_data = data[data["id"] == subject]
92-
# Remove NA values
93-
subject_data = subject_data.dropna(subset=["gl"])
94-
95-
if len(subject_data) == 0:
96-
continue
97-
98-
# Calculate hypo_index
99-
hypo_values = LLTR - subject_data[subject_data["gl"] < LLTR]["gl"]
100-
hypo_index = np.sum(hypo_values**b) / (len(subject_data) * d)
101-
102-
result.append({"id": subject, "hypo_index": hypo_index})
103-
104-
# Convert to DataFrame
105-
out = pd.DataFrame(result)
106-
107-
# Remove id column if input was a Series
108-
if is_vector and not out.empty:
109-
out = out.drop("id", axis=1)
110-
72+
out = data.groupby('id').agg(
73+
hypo_index = ("gl", lambda x: hypo_index_single(x, LLTR, b, d))
74+
).reset_index()
11175
return out
76+
77+
def hypo_index_single(
78+
gl: pd.Series, LLTR: int = 80, b: float = 2, d: int = 30
79+
) -> float:
80+
"""
81+
Calculate Hypoglycemia Index for a single subject.
82+
"""
83+
gl = gl.dropna()
84+
if len(gl) == 0:
85+
return np.nan
86+
# Calculate hypo_index
87+
hypo_values = LLTR - gl[gl < LLTR]
88+
hypo_index = np.sum(hypo_values**b) / (len(gl) * d)
89+
return hypo_index

tests/test_hyper_index.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,29 @@ def test_hyper_index_basic():
101101
subject2_index = result[result["id"] == "subject2"]["hyper_index"].iloc[0]
102102
assert subject1_index > subject2_index
103103

104+
def test_hyper_index_list_input():
105+
106+
# Create test data as Series
107+
data = [150, 200, 180, 130, 190, 160]
108+
109+
# Calculate hyper_index
110+
result = iglu.hyper_index(data)
111+
expected = 1.453976
112+
# Check output format
113+
assert isinstance(result, float)
114+
np.testing.assert_allclose(result, expected, rtol=1e-3)
115+
116+
def test_hyper_index_numpy_array_input():
117+
118+
# Create test data as Series
119+
data = np.array([150, 200, 180, 130, 190, 160])
120+
121+
# Calculate hyper_index
122+
result = iglu.hyper_index(data)
123+
expected = 1.453976
124+
# Check output format
125+
assert isinstance(result, float)
126+
np.testing.assert_allclose(result, expected, rtol=1e-3)
104127

105128
def test_hyper_index_series_input():
106129
"""Test hyper_index calculation with Series input."""
@@ -109,15 +132,11 @@ def test_hyper_index_series_input():
109132

110133
# Calculate hyper_index
111134
result = iglu.hyper_index(data)
112-
135+
expected = 1.453976
113136
# Check output format
114-
assert isinstance(result, pd.DataFrame)
115-
assert "hyper_index" in result.columns
116-
assert "id" not in result.columns
117-
assert len(result) == 1
137+
assert isinstance(result, float)
138+
np.testing.assert_allclose(result, expected, rtol=1e-3)
118139

119-
# Check that hyper_index value is non-negative
120-
assert result["hyper_index"].iloc[0] >= 0
121140

122141

123142
def test_hyper_index_custom_parameters():

tests/test_hypo_index.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,27 @@ def test_hypo_index_series_input():
110110

111111
# Calculate hypo_index
112112
result = iglu.hypo_index(data)
113+
expected = 7.638889
113114

114115
# Check output format
115-
assert isinstance(result, pd.DataFrame)
116-
assert "hypo_index" in result.columns
117-
assert "id" not in result.columns
118-
assert len(result) == 1
116+
assert isinstance(result, float)
117+
np.testing.assert_allclose(result, expected, rtol=1e-3)
119118

120-
# Check that hypo_index value is non-negative
121-
assert result["hypo_index"].iloc[0] >= 0
119+
def test_hypo_index_list_input():
120+
"""Test hypo_index calculation with list input."""
121+
data = [70, 60, 75, 65, 85, 55]
122+
result = iglu.hypo_index(data)
123+
expected = 7.638889
124+
assert isinstance(result, float)
125+
np.testing.assert_allclose(result, expected, rtol=1e-3)
126+
127+
def test_hypo_index_numpy_array_input():
128+
"""Test hypo_index calculation with numpy array input."""
129+
data = np.array([70, 60, 75, 65, 85, 55])
130+
result = iglu.hypo_index(data)
131+
expected = 7.638889
132+
assert isinstance(result, float)
133+
np.testing.assert_allclose(result, expected, rtol=1e-3)
122134

123135

124136
def test_hypo_index_custom_parameters():

0 commit comments

Comments
 (0)