rgwfuncs 0.0.25__py3-none-any.whl → 0.0.27__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.
- rgwfuncs/__init__.py +1 -1
- rgwfuncs/algebra_lib.py +309 -29
- rgwfuncs/df_lib.py +43 -14
- rgwfuncs/docs_lib.py +7 -5
- rgwfuncs/str_lib.py +6 -6
- {rgwfuncs-0.0.25.dist-info → rgwfuncs-0.0.27.dist-info}/METADATA +61 -1
- rgwfuncs-0.0.27.dist-info/RECORD +11 -0
- rgwfuncs-0.0.25.dist-info/RECORD +0 -11
- {rgwfuncs-0.0.25.dist-info → rgwfuncs-0.0.27.dist-info}/LICENSE +0 -0
- {rgwfuncs-0.0.25.dist-info → rgwfuncs-0.0.27.dist-info}/WHEEL +0 -0
- {rgwfuncs-0.0.25.dist-info → rgwfuncs-0.0.27.dist-info}/entry_points.txt +0 -0
- {rgwfuncs-0.0.25.dist-info → rgwfuncs-0.0.27.dist-info}/top_level.txt +0 -0
rgwfuncs/__init__.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# This file is automatically generated
|
2
2
|
# Dynamically importing functions from modules
|
3
3
|
|
4
|
-
from .algebra_lib import compute_algebraic_expression, get_prime_factors_latex, simplify_algebraic_expression, solve_algebraic_expression
|
4
|
+
from .algebra_lib import compute_algebraic_expression, compute_matrix_operation, compute_ordered_series_operation, get_prime_factors_latex, simplify_algebraic_expression, solve_algebraic_expression
|
5
5
|
from .df_lib import append_columns, append_percentile_classification_column, append_ranged_classification_column, append_ranged_date_classification_column, append_rows, append_xgb_labels, append_xgb_logistic_regression_predictions, append_xgb_regression_predictions, bag_union_join, bottom_n_unique_values, cascade_sort, delete_rows, drop_duplicates, drop_duplicates_retain_first, drop_duplicates_retain_last, filter_dataframe, filter_indian_mobiles, first_n_rows, from_raw_data, insert_dataframe_in_sqlite_database, last_n_rows, left_join, limit_dataframe, load_data_from_path, load_data_from_query, load_data_from_sqlite_path, mask_against_dataframe, mask_against_dataframe_converse, numeric_clean, order_columns, print_correlation, print_dataframe, print_memory_usage, print_n_frequency_cascading, print_n_frequency_linear, rename_columns, retain_columns, right_join, send_data_to_email, send_data_to_slack, send_dataframe_via_telegram, sync_dataframe_to_sqlite_database, top_n_unique_values, union_join, update_rows
|
6
6
|
from .docs_lib import docs
|
7
7
|
from .str_lib import send_telegram_message
|
rgwfuncs/algebra_lib.py
CHANGED
@@ -1,10 +1,30 @@
|
|
1
1
|
import re
|
2
2
|
import math
|
3
|
+
import ast
|
4
|
+
# import numpy as np
|
3
5
|
from sympy import symbols, latex, simplify, solve, diff, Expr
|
4
6
|
from sympy.parsing.sympy_parser import parse_expr
|
5
7
|
from typing import Tuple, List, Dict, Optional
|
6
8
|
|
9
|
+
|
7
10
|
def compute_algebraic_expression(expression: str) -> float:
|
11
|
+
"""
|
12
|
+
Computes the numerical result of a given algebraic expression.
|
13
|
+
|
14
|
+
Evaluates an algebraic expression provided as a string and returns the computed result.
|
15
|
+
Supports various arithmetic operations, including addition, subtraction, multiplication,
|
16
|
+
division, and modulo, as well as mathematical functions from the math module.
|
17
|
+
|
18
|
+
Parameters:
|
19
|
+
expression (str): The algebraic expression to compute. This should be a string consisting
|
20
|
+
of arithmetic operations and supported math module functions.
|
21
|
+
|
22
|
+
Returns:
|
23
|
+
float: The evaluated numerical result of the expression.
|
24
|
+
|
25
|
+
Raises:
|
26
|
+
ValueError: If the expression cannot be evaluated due to syntax errors or other issues.
|
27
|
+
"""
|
8
28
|
try:
|
9
29
|
# Direct numerical evaluation
|
10
30
|
# Safely evaluate the expression using the math module
|
@@ -15,10 +35,23 @@ def compute_algebraic_expression(expression: str) -> float:
|
|
15
35
|
except Exception as e:
|
16
36
|
raise ValueError(f"Error computing expression: {e}")
|
17
37
|
|
38
|
+
|
18
39
|
def simplify_algebraic_expression(expression: str) -> str:
|
40
|
+
"""
|
41
|
+
Simplifies an algebraic expression and returns it in LaTeX format.
|
42
|
+
|
43
|
+
Takes an algebraic expression written in Python syntax and simplifies it. The result is
|
44
|
+
returned as a LaTeX formatted string, suitable for academic or professional documentation.
|
19
45
|
|
46
|
+
Parameters:
|
47
|
+
expression (str): The algebraic expression to simplify.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
str: The simplified expression represented as a LaTeX string.
|
51
|
+
"""
|
20
52
|
|
21
|
-
def recursive_parse_function_call(
|
53
|
+
def recursive_parse_function_call(
|
54
|
+
func_call: str, prefix: str, sym_vars: Dict[str, Expr]) -> Tuple[str, List[Expr]]:
|
22
55
|
# print(f"Parsing function call: {func_call}")
|
23
56
|
|
24
57
|
# Match the function name and arguments
|
@@ -30,7 +63,8 @@ def simplify_algebraic_expression(expression: str) -> str:
|
|
30
63
|
args_str = match.group(2)
|
31
64
|
|
32
65
|
# Check if it's a list for np
|
33
|
-
if prefix == 'np' and args_str.startswith(
|
66
|
+
if prefix == 'np' and args_str.startswith(
|
67
|
+
"[") and args_str.endswith("]"):
|
34
68
|
parsed_args = [ast.literal_eval(args_str.strip())]
|
35
69
|
else:
|
36
70
|
parsed_args = []
|
@@ -38,77 +72,98 @@ def simplify_algebraic_expression(expression: str) -> str:
|
|
38
72
|
for arg in raw_args:
|
39
73
|
arg = arg.strip()
|
40
74
|
if re.match(r'\w+\.\w+\(', arg):
|
41
|
-
# Recursively evaluate the argument if it's another
|
42
|
-
|
43
|
-
|
75
|
+
# Recursively evaluate the argument if it's another
|
76
|
+
# function call
|
77
|
+
arg_val = recursive_eval_func(
|
78
|
+
re.match(r'\w+\.\w+\(.*\)', arg), sym_vars)
|
79
|
+
parsed_args.append(
|
80
|
+
parse_expr(
|
81
|
+
arg_val,
|
82
|
+
local_dict=sym_vars))
|
44
83
|
else:
|
45
84
|
parsed_args.append(parse_expr(arg, local_dict=sym_vars))
|
46
85
|
|
47
86
|
# print(f"Function name: {func_name}, Parsed arguments: {parsed_args}")
|
48
87
|
return func_name, parsed_args
|
49
88
|
|
50
|
-
|
51
89
|
def recursive_eval_func(match: re.Match, sym_vars: Dict[str, Expr]) -> str:
|
52
90
|
# print("152", match)
|
53
91
|
func_call = match.group(0)
|
54
92
|
# print(f"153 Evaluating function call: {func_call}")
|
55
93
|
|
56
94
|
if func_call.startswith("np."):
|
57
|
-
func_name, args = recursive_parse_function_call(
|
95
|
+
func_name, args = recursive_parse_function_call(
|
96
|
+
func_call, 'np', sym_vars)
|
58
97
|
if func_name == 'diff':
|
59
98
|
expr = args[0]
|
60
99
|
if isinstance(expr, list):
|
61
100
|
# Calculate discrete difference
|
62
|
-
diff_result = [expr[i] - expr[i - 1]
|
101
|
+
diff_result = [expr[i] - expr[i - 1]
|
102
|
+
for i in range(1, len(expr))]
|
63
103
|
return str(diff_result)
|
64
104
|
# Perform symbolic differentiation
|
65
105
|
diff_result = diff(expr)
|
66
106
|
return str(diff_result)
|
67
107
|
|
68
108
|
if func_call.startswith("math."):
|
69
|
-
func_name, args = recursive_parse_function_call(
|
109
|
+
func_name, args = recursive_parse_function_call(
|
110
|
+
func_call, 'math', sym_vars)
|
70
111
|
if hasattr(math, func_name):
|
71
112
|
result = getattr(math, func_name)(*args)
|
72
113
|
return str(result)
|
73
114
|
|
74
115
|
if func_call.startswith("sym."):
|
75
|
-
initial_method_match = re.match(
|
116
|
+
initial_method_match = re.match(
|
117
|
+
r'(sym\.\w+\([^()]*\))(\.(\w+)\((.*?)\))*', func_call, re.DOTALL)
|
76
118
|
if initial_method_match:
|
77
119
|
base_expr_str = initial_method_match.group(1)
|
78
|
-
base_func_name, base_args = recursive_parse_function_call(
|
120
|
+
base_func_name, base_args = recursive_parse_function_call(
|
121
|
+
base_expr_str, 'sym', sym_vars)
|
79
122
|
if base_func_name == 'solve':
|
80
123
|
solutions = solve(base_args[0], base_args[1])
|
81
124
|
# print(f"Solutions found: {solutions}")
|
82
125
|
|
83
|
-
method_chain = re.findall(
|
84
|
-
|
126
|
+
method_chain = re.findall(
|
127
|
+
r'\.(\w+)\((.*?)\)', func_call, re.DOTALL)
|
128
|
+
final_solutions = [execute_chained_methods(sol, [(m, [method_args.strip(
|
129
|
+
)]) for m, method_args in method_chain], sym_vars) for sol in solutions]
|
85
130
|
|
86
|
-
return "[" + ",".join(latex(simplify(sol))
|
131
|
+
return "[" + ",".join(latex(simplify(sol))
|
132
|
+
for sol in final_solutions) + "]"
|
87
133
|
|
88
134
|
raise ValueError(f"Unknown function call: {func_call}")
|
89
135
|
|
90
|
-
def execute_chained_methods(sym_expr: Expr,
|
136
|
+
def execute_chained_methods(sym_expr: Expr,
|
137
|
+
method_chain: List[Tuple[str,
|
138
|
+
List[str]]],
|
139
|
+
sym_vars: Dict[str,
|
140
|
+
Expr]) -> Expr:
|
91
141
|
for method_name, method_args in method_chain:
|
92
142
|
# print(f"Executing method: {method_name} with arguments: {method_args}")
|
93
143
|
method = getattr(sym_expr, method_name, None)
|
94
144
|
if method:
|
95
145
|
if method_name == 'subs' and isinstance(method_args[0], dict):
|
96
146
|
kwargs = method_args[0]
|
97
|
-
kwargs = {
|
147
|
+
kwargs = {
|
148
|
+
parse_expr(
|
149
|
+
k,
|
150
|
+
local_dict=sym_vars): parse_expr(
|
151
|
+
v,
|
152
|
+
local_dict=sym_vars) for k,
|
153
|
+
v in kwargs.items()}
|
98
154
|
sym_expr = method(kwargs)
|
99
155
|
else:
|
100
|
-
args = [parse_expr(arg.strip(), local_dict=sym_vars)
|
156
|
+
args = [parse_expr(arg.strip(), local_dict=sym_vars)
|
157
|
+
for arg in method_args]
|
101
158
|
sym_expr = method(*args)
|
102
159
|
# print(f"Result after {method_name}: {sym_expr}")
|
103
160
|
return sym_expr
|
104
161
|
|
105
|
-
|
106
|
-
|
107
162
|
variable_names = set(re.findall(r'\b[a-zA-Z]\w*\b', expression))
|
108
163
|
sym_vars = {var: symbols(var) for var in variable_names}
|
109
164
|
|
110
165
|
patterns = {
|
111
|
-
#"numpy_diff_brackets": r"np\.diff\(\[.*?\]\)",
|
166
|
+
# "numpy_diff_brackets": r"np\.diff\(\[.*?\]\)",
|
112
167
|
"numpy_diff_no_brackets": r"np\.diff\([^()]*\)",
|
113
168
|
"math_functions": r"math\.\w+\((?:[^()]*(?:\([^()]*\)[^()]*)*)\)",
|
114
169
|
# "sympy_functions": r"sym\.\w+\([^()]*\)(?:\.\w+\([^()]*\))?",
|
@@ -117,11 +172,14 @@ def simplify_algebraic_expression(expression: str) -> str:
|
|
117
172
|
function_pattern = '|'.join(patterns.values())
|
118
173
|
|
119
174
|
# Use a lambda function to pass additional arguments
|
120
|
-
processed_expression = re.sub(
|
175
|
+
processed_expression = re.sub(
|
176
|
+
function_pattern, lambda match: recursive_eval_func(
|
177
|
+
match, sym_vars), expression)
|
121
178
|
# print("Level 2 processed_expression:", processed_expression)
|
122
179
|
|
123
180
|
try:
|
124
|
-
if processed_expression.startswith(
|
181
|
+
if processed_expression.startswith(
|
182
|
+
'[') and processed_expression.endswith(']'):
|
125
183
|
return processed_expression
|
126
184
|
|
127
185
|
expr = parse_expr(processed_expression, local_dict=sym_vars)
|
@@ -136,7 +194,28 @@ def simplify_algebraic_expression(expression: str) -> str:
|
|
136
194
|
except Exception as e:
|
137
195
|
raise ValueError(f"Error simplifying expression: {e}")
|
138
196
|
|
139
|
-
|
197
|
+
|
198
|
+
def solve_algebraic_expression(
|
199
|
+
expression: str, variable: str, subs: Optional[Dict[str, float]] = None) -> str:
|
200
|
+
"""
|
201
|
+
Solves an algebraic equation for a specified variable and returns solutions in LaTeX format.
|
202
|
+
|
203
|
+
Solves the given equation for a designated variable. May optionally include substitutions
|
204
|
+
for other variables in the equation. The solutions are provided as a LaTeX formatted string.
|
205
|
+
|
206
|
+
Parameters:
|
207
|
+
expression (str): The algebraic equation to solve.
|
208
|
+
variable (str): The variable to solve the equation for.
|
209
|
+
subs (Optional[Dict[str, float]]): An optional dictionary of substitutions for variables
|
210
|
+
in the equation.
|
211
|
+
|
212
|
+
Returns:
|
213
|
+
str: The solutions of the equation, formatted as a LaTeX string.
|
214
|
+
|
215
|
+
Raises:
|
216
|
+
ValueError: If the equation cannot be solved due to errors in expression or parameters.
|
217
|
+
"""
|
218
|
+
|
140
219
|
try:
|
141
220
|
# Create symbols for the variables in the expression
|
142
221
|
variable_symbols = set(re.findall(r'\b[a-zA-Z]\w*\b', expression))
|
@@ -153,7 +232,9 @@ def solve_algebraic_expression(expression: str, variable: str, subs: Optional[Di
|
|
153
232
|
solutions = [simplify(sol.subs(subs_symbols)) for sol in solutions]
|
154
233
|
|
155
234
|
# Convert solutions to LaTeX strings if possible
|
156
|
-
latex_solutions = [
|
235
|
+
latex_solutions = [
|
236
|
+
latex(
|
237
|
+
simplify(sol)) if sol.free_symbols else str(sol) for sol in solutions]
|
157
238
|
result = r"\left[" + ", ".join(latex_solutions) + r"\right]"
|
158
239
|
print("158", result)
|
159
240
|
return result
|
@@ -162,11 +243,212 @@ def solve_algebraic_expression(expression: str, variable: str, subs: Optional[Di
|
|
162
243
|
raise ValueError(f"Error solving the expression: {e}")
|
163
244
|
|
164
245
|
|
246
|
+
def compute_matrix_operation(expression: str) -> str:
|
247
|
+
"""
|
248
|
+
Computes the result of a matrix-like operation on 1D or 2D list inputs and returns it as a LaTeX string.
|
249
|
+
|
250
|
+
Evaluates an operation where lists are treated as matrices, performs operations on them sequentially, and
|
251
|
+
returns the result formatted as a LaTeX-style string.
|
252
|
+
|
253
|
+
Parameters:
|
254
|
+
expression (str): The matrix operation expression to compute. Example format includes operations such as "+", "-", "*", "/".
|
255
|
+
|
256
|
+
Returns:
|
257
|
+
str: The LaTeX-formatted string representation of the result or a message indicating an error in dimensions.
|
258
|
+
"""
|
259
|
+
|
260
|
+
def elementwise_operation(matrix1: List[List[float]], matrix2: List[List[float]], operation: str) -> List[List[float]]:
|
261
|
+
if len(matrix1) != len(matrix2) or any(len(row1) != len(row2) for row1, row2 in zip(matrix1, matrix2)):
|
262
|
+
return "Operations between matrices must involve matrices of the same dimension"
|
263
|
+
|
264
|
+
if operation == '+':
|
265
|
+
return [[a + b for a, b in zip(row1, row2)] for row1, row2 in zip(matrix1, matrix2)]
|
266
|
+
elif operation == '-':
|
267
|
+
return [[a - b for a, b in zip(row1, row2)] for row1, row2 in zip(matrix1, matrix2)]
|
268
|
+
elif operation == '*':
|
269
|
+
return [[a * b for a, b in zip(row1, row2)] for row1, row2 in zip(matrix1, matrix2)]
|
270
|
+
elif operation == '/':
|
271
|
+
return [[a / b for a, b in zip(row1, row2) if b != 0] for row1, row2 in zip(matrix1, matrix2)]
|
272
|
+
else:
|
273
|
+
return f"Unsupported operation {operation}"
|
274
|
+
|
275
|
+
try:
|
276
|
+
# Use a stack-based method to properly parse matrices
|
277
|
+
elements = []
|
278
|
+
buffer = ''
|
279
|
+
bracket_level = 0
|
280
|
+
operators = set('+-*/')
|
281
|
+
|
282
|
+
for char in expression:
|
283
|
+
if char == '[':
|
284
|
+
if bracket_level == 0 and buffer.strip():
|
285
|
+
elements.append(buffer.strip())
|
286
|
+
buffer = ''
|
287
|
+
bracket_level += 1
|
288
|
+
elif char == ']':
|
289
|
+
bracket_level -= 1
|
290
|
+
if bracket_level == 0:
|
291
|
+
buffer += char
|
292
|
+
elements.append(buffer.strip())
|
293
|
+
buffer = ''
|
294
|
+
continue
|
295
|
+
if bracket_level == 0 and char in operators:
|
296
|
+
if buffer.strip():
|
297
|
+
elements.append(buffer.strip())
|
298
|
+
buffer = ''
|
299
|
+
elements.append(char)
|
300
|
+
else:
|
301
|
+
buffer += char
|
302
|
+
|
303
|
+
if buffer.strip():
|
304
|
+
elements.append(buffer.strip())
|
305
|
+
|
306
|
+
result = ast.literal_eval(elements[0])
|
307
|
+
|
308
|
+
if not any(isinstance(row, list) for row in result):
|
309
|
+
result = [result] # Convert 1D matrix to 2D
|
310
|
+
|
311
|
+
i = 1
|
312
|
+
while i < len(elements):
|
313
|
+
operation = elements[i]
|
314
|
+
matrix = ast.literal_eval(elements[i + 1])
|
315
|
+
|
316
|
+
if not any(isinstance(row, list) for row in matrix):
|
317
|
+
matrix = [matrix]
|
318
|
+
|
319
|
+
operation_result = elementwise_operation(result, matrix, operation)
|
320
|
+
|
321
|
+
# Check if the operation resulted in an error message
|
322
|
+
if isinstance(operation_result, str):
|
323
|
+
return operation_result
|
324
|
+
|
325
|
+
result = operation_result
|
326
|
+
i += 2
|
327
|
+
|
328
|
+
# Create a LaTeX-style matrix representation
|
329
|
+
matrix_entries = '\\\\'.join(' & '.join(str(x) for x in row) for row in result)
|
330
|
+
return r"\begin{bmatrix}" + f"{matrix_entries}" + r"\end{bmatrix}"
|
331
|
+
|
332
|
+
except Exception as e:
|
333
|
+
return f"Error computing matrix operation: {e}"
|
334
|
+
|
335
|
+
|
336
|
+
def compute_ordered_series_operation(expression: str) -> str:
|
337
|
+
"""
|
338
|
+
Computes the result of operations on ordered series expressed as 1D lists, including discrete difference (ddd),
|
339
|
+
and returns it as a string.
|
340
|
+
|
341
|
+
The function first applies the discrete difference operator to any series where applicable, then evaluates
|
342
|
+
arithmetic operations between series.
|
343
|
+
|
344
|
+
Parameters:
|
345
|
+
expression (str): The series operation expression to compute. Includes operations "+", "-", "*", "/", and "ddd".
|
346
|
+
|
347
|
+
Returns:
|
348
|
+
str: The string representation of the resultant series after performing operations, or an error message
|
349
|
+
if the series lengths do not match.
|
350
|
+
|
351
|
+
Raises:
|
352
|
+
ValueError: If the expression cannot be evaluated.
|
353
|
+
"""
|
354
|
+
|
355
|
+
def elementwise_operation(series1: List[float], series2: List[float], operation: str) -> List[float]:
|
356
|
+
if len(series1) != len(series2):
|
357
|
+
return "Operations between ordered series must involve series of equal length"
|
358
|
+
|
359
|
+
if operation == '+':
|
360
|
+
return [a + b for a, b in zip(series1, series2)]
|
361
|
+
elif operation == '-':
|
362
|
+
return [a - b for a, b in zip(series1, series2)]
|
363
|
+
elif operation == '*':
|
364
|
+
return [a * b for a, b in zip(series1, series2)]
|
365
|
+
elif operation == '/':
|
366
|
+
return [a / b for a, b in zip(series1, series2) if b != 0]
|
367
|
+
else:
|
368
|
+
return f"Unsupported operation {operation}"
|
369
|
+
|
370
|
+
def discrete_difference(series: list) -> list:
|
371
|
+
"""Computes the discrete difference of a series."""
|
372
|
+
return [series[i + 1] - series[i] for i in range(len(series) - 1)]
|
373
|
+
|
374
|
+
try:
|
375
|
+
# First, apply the discrete difference operator where applicable
|
376
|
+
pattern = r'ddd\((\[[^\]]*\])\)'
|
377
|
+
matches = re.findall(pattern, expression)
|
378
|
+
|
379
|
+
for match in matches:
|
380
|
+
if match.strip() == '[]':
|
381
|
+
result_series = [] # Handle the empty list case
|
382
|
+
else:
|
383
|
+
series = ast.literal_eval(match)
|
384
|
+
result_series = discrete_difference(series)
|
385
|
+
expression = expression.replace(f'ddd({match})', str(result_series))
|
386
|
+
|
387
|
+
# Now parse and evaluate the full expression with basic operations
|
388
|
+
elements = []
|
389
|
+
buffer = ''
|
390
|
+
bracket_level = 0
|
391
|
+
operators = set('+-*/')
|
392
|
+
|
393
|
+
for char in expression:
|
394
|
+
if char == '[':
|
395
|
+
if bracket_level == 0 and buffer.strip():
|
396
|
+
elements.append(buffer.strip())
|
397
|
+
buffer = ''
|
398
|
+
bracket_level += 1
|
399
|
+
elif char == ']':
|
400
|
+
bracket_level -= 1
|
401
|
+
if bracket_level == 0:
|
402
|
+
buffer += char
|
403
|
+
elements.append(buffer.strip())
|
404
|
+
buffer = ''
|
405
|
+
continue
|
406
|
+
if bracket_level == 0 and char in operators:
|
407
|
+
if buffer.strip():
|
408
|
+
elements.append(buffer.strip())
|
409
|
+
buffer = ''
|
410
|
+
elements.append(char)
|
411
|
+
else:
|
412
|
+
buffer += char
|
413
|
+
|
414
|
+
if buffer.strip():
|
415
|
+
elements.append(buffer.strip())
|
416
|
+
|
417
|
+
result = ast.literal_eval(elements[0])
|
418
|
+
|
419
|
+
i = 1
|
420
|
+
while i < len(elements):
|
421
|
+
operation = elements[i]
|
422
|
+
series = ast.literal_eval(elements[i + 1])
|
423
|
+
operation_result = elementwise_operation(result, series, operation)
|
424
|
+
|
425
|
+
# Check if the operation resulted in an error message
|
426
|
+
if isinstance(operation_result, str):
|
427
|
+
return operation_result
|
428
|
+
|
429
|
+
result = operation_result
|
430
|
+
i += 2
|
431
|
+
|
432
|
+
return str(result)
|
433
|
+
|
434
|
+
except Exception as e:
|
435
|
+
return f"Error computing ordered series operation: {e}"
|
436
|
+
|
165
437
|
|
166
438
|
def get_prime_factors_latex(n: int) -> str:
|
167
439
|
"""
|
168
|
-
|
440
|
+
Computes the prime factors of a number and returns the factorization as a LaTeX string.
|
441
|
+
|
442
|
+
Determines the prime factorization of the given integer. The result is formatted as a LaTeX
|
443
|
+
string, enabling easy integration into documents or presentations that require mathematical notation.
|
444
|
+
|
445
|
+
Parameters:
|
446
|
+
n (int): The number for which to compute prime factors.
|
447
|
+
|
448
|
+
Returns:
|
449
|
+
str: The LaTeX representation of the prime factorization.
|
169
450
|
"""
|
451
|
+
|
170
452
|
factors = []
|
171
453
|
while n % 2 == 0:
|
172
454
|
factors.append(2)
|
@@ -179,8 +461,6 @@ def get_prime_factors_latex(n: int) -> str:
|
|
179
461
|
factors.append(n)
|
180
462
|
|
181
463
|
factor_counts = {factor: factors.count(factor) for factor in set(factors)}
|
182
|
-
latex_factors = [f"{factor}^{{{count}}}" if count > 1 else str(
|
464
|
+
latex_factors = [f"{factor}^{{{count}}}" if count > 1 else str(
|
465
|
+
factor) for factor, count in factor_counts.items()]
|
183
466
|
return " \\cdot ".join(latex_factors)
|
184
|
-
|
185
|
-
|
186
|
-
|
rgwfuncs/df_lib.py
CHANGED
@@ -21,8 +21,8 @@ from email.mime.base import MIMEBase
|
|
21
21
|
from email import encoders
|
22
22
|
from googleapiclient.discovery import build
|
23
23
|
import base64
|
24
|
-
import inspect
|
25
|
-
from typing import Optional,
|
24
|
+
# import inspect
|
25
|
+
from typing import Optional, Dict, List, Tuple, Any
|
26
26
|
import warnings
|
27
27
|
|
28
28
|
# Suppress all FutureWarnings
|
@@ -798,7 +798,12 @@ def print_dataframe(df: pd.DataFrame, source: Optional[str] = None) -> None:
|
|
798
798
|
gc.collect()
|
799
799
|
|
800
800
|
|
801
|
-
def send_dataframe_via_telegram(
|
801
|
+
def send_dataframe_via_telegram(
|
802
|
+
df: pd.DataFrame,
|
803
|
+
bot_name: str,
|
804
|
+
message: Optional[str] = None,
|
805
|
+
as_file: bool = True,
|
806
|
+
remove_after_send: bool = True) -> None:
|
802
807
|
"""
|
803
808
|
Send a DataFrame via Telegram using a specified bot configuration.
|
804
809
|
|
@@ -1635,7 +1640,12 @@ def print_n_frequency_cascading(
|
|
1635
1640
|
report = generate_cascade_report(df, columns, n, order_by)
|
1636
1641
|
print(json.dumps(report, indent=2))
|
1637
1642
|
|
1638
|
-
|
1643
|
+
|
1644
|
+
def print_n_frequency_linear(
|
1645
|
+
df: pd.DataFrame,
|
1646
|
+
n: int,
|
1647
|
+
columns: list,
|
1648
|
+
order_by: str = "FREQ_DESC") -> None:
|
1639
1649
|
"""
|
1640
1650
|
Print the linear frequency of top n values for specified columns.
|
1641
1651
|
|
@@ -1682,23 +1692,36 @@ def print_n_frequency_linear(df: pd.DataFrame, n: int, columns: list, order_by:
|
|
1682
1692
|
return val
|
1683
1693
|
|
1684
1694
|
def sort_frequency(frequency, order_by):
|
1685
|
-
keys = frequency.keys()
|
1695
|
+
# keys = frequency.keys()
|
1686
1696
|
|
1687
|
-
# Convert keys to numerical values where possible, leaving `NaN` as a
|
1688
|
-
|
1697
|
+
# Convert keys to numerical values where possible, leaving `NaN` as a
|
1698
|
+
# special string
|
1699
|
+
# parsed_keys = [(try_parse_numeric(key), key) for key in keys]
|
1689
1700
|
|
1690
1701
|
if order_by in {"BY_KEYS_ASC", "BY_KEYS_DESC"}:
|
1691
1702
|
reverse = order_by == "BY_KEYS_DESC"
|
1692
|
-
sorted_items = sorted(
|
1703
|
+
sorted_items = sorted(
|
1704
|
+
frequency.items(),
|
1705
|
+
key=lambda item: try_parse_numeric(
|
1706
|
+
item[0]),
|
1707
|
+
reverse=reverse)
|
1693
1708
|
else:
|
1694
1709
|
if order_by == "ASC":
|
1695
|
-
sorted_items = sorted(
|
1710
|
+
sorted_items = sorted(
|
1711
|
+
frequency.items(), key=lambda item: item[0])
|
1696
1712
|
elif order_by == "DESC":
|
1697
|
-
sorted_items = sorted(
|
1713
|
+
sorted_items = sorted(
|
1714
|
+
frequency.items(),
|
1715
|
+
key=lambda item: item[0],
|
1716
|
+
reverse=True)
|
1698
1717
|
elif order_by == "FREQ_ASC":
|
1699
|
-
sorted_items = sorted(
|
1718
|
+
sorted_items = sorted(
|
1719
|
+
frequency.items(), key=lambda item: item[1])
|
1700
1720
|
else: # Default to "FREQ_DESC"
|
1701
|
-
sorted_items = sorted(
|
1721
|
+
sorted_items = sorted(
|
1722
|
+
frequency.items(),
|
1723
|
+
key=lambda item: item[1],
|
1724
|
+
reverse=True)
|
1702
1725
|
|
1703
1726
|
return dict(sorted_items)
|
1704
1727
|
|
@@ -1850,7 +1873,10 @@ def right_join(
|
|
1850
1873
|
return df1.merge(df2, how='right', left_on=left_on, right_on=right_on)
|
1851
1874
|
|
1852
1875
|
|
1853
|
-
def insert_dataframe_in_sqlite_database(
|
1876
|
+
def insert_dataframe_in_sqlite_database(
|
1877
|
+
db_path: str,
|
1878
|
+
tablename: str,
|
1879
|
+
df: pd.DataFrame) -> None:
|
1854
1880
|
"""
|
1855
1881
|
Inserts a Pandas DataFrame into a SQLite database table.
|
1856
1882
|
|
@@ -1912,7 +1938,10 @@ def insert_dataframe_in_sqlite_database(db_path: str, tablename: str, df: pd.Dat
|
|
1912
1938
|
df.to_sql(tablename, conn, if_exists='append', index=False)
|
1913
1939
|
|
1914
1940
|
|
1915
|
-
def sync_dataframe_to_sqlite_database(
|
1941
|
+
def sync_dataframe_to_sqlite_database(
|
1942
|
+
db_path: str,
|
1943
|
+
tablename: str,
|
1944
|
+
df: pd.DataFrame) -> None:
|
1916
1945
|
"""
|
1917
1946
|
Processes and saves a DataFrame to an SQLite database, adding a timestamp column
|
1918
1947
|
and replacing the existing table if needed. Creates the table if it does not exist.
|
rgwfuncs/docs_lib.py
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
import os
|
2
2
|
import inspect
|
3
|
-
from typing import
|
3
|
+
from typing import Optional
|
4
4
|
import warnings
|
5
5
|
|
6
6
|
# Suppress all FutureWarnings
|
7
7
|
warnings.filterwarnings("ignore", category=FutureWarning)
|
8
8
|
|
9
|
+
|
9
10
|
def docs(method_type_filter: Optional[str] = None) -> None:
|
10
11
|
"""
|
11
12
|
Print a list of function names in alphabetical order from all modules.
|
12
13
|
If method_type_filter is specified, print the docstrings of the functions
|
13
|
-
that match the filter based on a substring. Using '*' as a filter will print
|
14
|
+
that match the filter based on a substring. Using '*' as a filter will print
|
14
15
|
the docstrings for all functions.
|
15
16
|
|
16
17
|
Parameters:
|
@@ -41,9 +42,10 @@ def docs(method_type_filter: Optional[str] = None) -> None:
|
|
41
42
|
# List function names
|
42
43
|
function_names = sorted(functions.keys())
|
43
44
|
for name in function_names:
|
44
|
-
# If a filter is provided or '*', check if the function name
|
45
|
-
|
45
|
+
# If a filter is provided or '*', check if the function name
|
46
|
+
# contains the filter
|
47
|
+
if method_type_filter and (
|
48
|
+
method_type_filter == '*' or method_type_filter in name):
|
46
49
|
docstring: Optional[str] = functions[name].__doc__
|
47
50
|
if docstring:
|
48
51
|
print(f"\n{name}:\n{docstring}")
|
49
|
-
|
rgwfuncs/str_lib.py
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import json
|
3
3
|
import requests
|
4
|
-
import
|
5
|
-
from typing import Tuple, Optional, Dict, Callable
|
4
|
+
from typing import Tuple
|
6
5
|
import warnings
|
7
6
|
|
8
7
|
# Suppress all FutureWarnings
|
@@ -37,19 +36,20 @@ def send_telegram_message(preset_name: str, message: str) -> None:
|
|
37
36
|
return preset
|
38
37
|
return None
|
39
38
|
|
40
|
-
def get_telegram_bot_details(
|
39
|
+
def get_telegram_bot_details(
|
40
|
+
config: dict, preset_name: str) -> Tuple[str, str]:
|
41
41
|
"""Retrieve the Telegram bot token and chat ID from the preset."""
|
42
42
|
preset = get_telegram_preset(config, preset_name)
|
43
43
|
if not preset:
|
44
|
-
raise RuntimeError(
|
44
|
+
raise RuntimeError(
|
45
|
+
f"Telegram bot preset '{preset_name}' not found in the configuration file")
|
45
46
|
|
46
47
|
bot_token = preset.get("bot_token")
|
47
48
|
chat_id = preset.get("chat_id")
|
48
49
|
|
49
50
|
if not bot_token or not chat_id:
|
50
51
|
raise RuntimeError(
|
51
|
-
f"Telegram bot token or chat ID for '{preset_name}' not found in the configuration file"
|
52
|
-
)
|
52
|
+
f"Telegram bot token or chat ID for '{preset_name}' not found in the configuration file")
|
53
53
|
|
54
54
|
return bot_token, chat_id
|
55
55
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: rgwfuncs
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.27
|
4
4
|
Summary: A functional programming paradigm for mathematical modelling and data science
|
5
5
|
Home-page: https://github.com/ryangerardwilson/rgwfunc
|
6
6
|
Author: Ryan Gerard Wilson
|
@@ -252,6 +252,66 @@ Computes prime factors of a number and presents them in LaTeX format.
|
|
252
252
|
|
253
253
|
--------------------------------------------------------------------------------
|
254
254
|
|
255
|
+
### 5. `compute_matrix_operation`
|
256
|
+
|
257
|
+
Computes the results of 1D or 2D matrix operations and formats them as LaTeX strings.
|
258
|
+
|
259
|
+
- **Parameters:**
|
260
|
+
- `expression` (str): A string representing a sequence of matrix operations involving either 1D or 2D lists. Supported operations include addition (`+`), subtraction (`-`), multiplication (`*`), and division (`/`).
|
261
|
+
|
262
|
+
- **Returns:**
|
263
|
+
- `str`: The LaTeX-formatted string representation of the computed matrix, or an error message if the operations cannot be performed due to dimensional mismatches.
|
264
|
+
|
265
|
+
- **Example:**
|
266
|
+
|
267
|
+
from rgwfuncs import compute_matrix_operation
|
268
|
+
|
269
|
+
# Example with addition of 2D matrices
|
270
|
+
result = compute_matrix_operation("[[2, 6, 9], [1, 3, 5]] + [[1, 2, 3], [4, 5, 6]]")
|
271
|
+
print(result) # Output: \begin{bmatrix}3 & 8 & 12\\5 & 8 & 11\end{bmatrix}
|
272
|
+
|
273
|
+
# Example of mixed operations with 1D matrices treated as 2D
|
274
|
+
result = compute_matrix_operation("[3, 6, 9] + [1, 2, 3] - [2, 2, 2]")
|
275
|
+
print(result) # Output: \begin{bmatrix}2 & 6 & 10\end{bmatrix}
|
276
|
+
|
277
|
+
# Example with dimension mismatch
|
278
|
+
result = compute_matrix_operation("[[4, 3, 51]] + [[1, 1]]")
|
279
|
+
print(result) # Output: Operations between matrices must involve matrices of the same dimension
|
280
|
+
|
281
|
+
This function performs elementwise operations on both 1D and 2D matrices represented as Python lists and formats the result as a LaTeX string. It handles operations sequentially from left to right and gracefully handles dimension mismatches by returning a meaningful message. It utilizes Python's `ast.literal_eval` for safe and robust parsing.
|
282
|
+
|
283
|
+
--------------------------------------------------------------------------------
|
284
|
+
|
285
|
+
### 6. `compute_ordered_series_operations`
|
286
|
+
|
287
|
+
Computes the result of operations on ordered series expressed as 1D lists, including the discrete difference operator `ddd`.
|
288
|
+
|
289
|
+
- **Parameters:**
|
290
|
+
- `expression` (str): A series operation expression. Supports operations such as "+", "-", "*", "/", and `ddd` for discrete differences.
|
291
|
+
|
292
|
+
- **Returns:**
|
293
|
+
- `str`: The string representation of the resultant series after performing operations, or an error message if series lengths do not match.
|
294
|
+
|
295
|
+
- **Example:**
|
296
|
+
|
297
|
+
from rgwfuncs import compute_ordered_series_operations
|
298
|
+
|
299
|
+
# Example with addition and discrete differences
|
300
|
+
result = compute_ordered_series_operations("ddd([2, 6, 9, 60]) + ddd([78, 79, 80])")
|
301
|
+
print(result) # Output: [4, 3, 51] + [1, 1]
|
302
|
+
|
303
|
+
# Example with elementwise subtraction
|
304
|
+
result = compute_ordered_series_operations("[10, 15, 21] - [5, 5, 5]")
|
305
|
+
print(result) # Output: [5, 10, 16]
|
306
|
+
|
307
|
+
# Example with length mismatch
|
308
|
+
result = compute_ordered_series_operations("[4, 3, 51] + [1, 1]")
|
309
|
+
print(result) # Output: Operations between ordered series must involve series of equal length
|
310
|
+
|
311
|
+
This function first applies the discrete difference operator to any series where applicable, then evaluates arithmetic operations between series. It returns a string representation of the result or an error message if the series lengths do not match. The function is robust, directly parsing and evaluating given series expressions with safety checks in place.
|
312
|
+
|
313
|
+
--------------------------------------------------------------------------------
|
314
|
+
|
255
315
|
## String Based Functions
|
256
316
|
|
257
317
|
### 1. send_telegram_message
|
@@ -0,0 +1,11 @@
|
|
1
|
+
rgwfuncs/__init__.py,sha256=6QXVaHomLh1AIbC-b-edLf-GS1oEqRT-JffHPNIKowA,1375
|
2
|
+
rgwfuncs/algebra_lib.py,sha256=VZS0d-sUGJvfHv00HmgD1htxBGbugsKkKuUKsJbLPkI,18205
|
3
|
+
rgwfuncs/df_lib.py,sha256=G_H3PXNVeseX2YLjkkrmO9eXA_7r29swUZlbPBDZjXA,66612
|
4
|
+
rgwfuncs/docs_lib.py,sha256=y3wSAOPO3qsA4HZ7xAtW8HimM8w-c8hjcEzMRLJ96ao,1960
|
5
|
+
rgwfuncs/str_lib.py,sha256=rtAdRlnSJIu3JhI-tA_A0wCiPK2m-zn5RoGpBxv_g-4,2228
|
6
|
+
rgwfuncs-0.0.27.dist-info/LICENSE,sha256=7EI8xVBu6h_7_JlVw-yPhhOZlpY9hP8wal7kHtqKT_E,1074
|
7
|
+
rgwfuncs-0.0.27.dist-info/METADATA,sha256=NSNgM-VFveOpzvmosZgjg7kSC9KovbyXspCTXCdMdrU,41874
|
8
|
+
rgwfuncs-0.0.27.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
9
|
+
rgwfuncs-0.0.27.dist-info/entry_points.txt,sha256=j-c5IOPIQ0252EaOV6j6STio56sbXl2C4ym_fQ0lXx0,43
|
10
|
+
rgwfuncs-0.0.27.dist-info/top_level.txt,sha256=aGuVIzWsKiV1f2gCb6mynx0zx5ma0B1EwPGFKVEMTi4,9
|
11
|
+
rgwfuncs-0.0.27.dist-info/RECORD,,
|
rgwfuncs-0.0.25.dist-info/RECORD
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
rgwfuncs/__init__.py,sha256=SZg1HPP5D_3QimoYFH8zongQ9D9XPZWp-Qi-MZglvXw,1315
|
2
|
-
rgwfuncs/algebra_lib.py,sha256=aayZogB2Rp9JAo5kVHpauqX_R346eI_rIuE5QNEMlKM,7789
|
3
|
-
rgwfuncs/df_lib.py,sha256=OfbnAii_RND_euTJVou9nJaDqRLNbIMTCbaBelAUDvk,66247
|
4
|
-
rgwfuncs/docs_lib.py,sha256=vlO8Rr6PYzyd2ZAenV_6t_iZJ3CoHja3PSLJverlAT4,1941
|
5
|
-
rgwfuncs/str_lib.py,sha256=PHvxAg7_mZ_xe7DWJiAQ-PQ2fkYddKe8G0iQ1L78aZ0,2252
|
6
|
-
rgwfuncs-0.0.25.dist-info/LICENSE,sha256=7EI8xVBu6h_7_JlVw-yPhhOZlpY9hP8wal7kHtqKT_E,1074
|
7
|
-
rgwfuncs-0.0.25.dist-info/METADATA,sha256=RQIG8bS4SFwHTycxQXpaYnyw2C8UIkQZEe7EfivMwao,38637
|
8
|
-
rgwfuncs-0.0.25.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
9
|
-
rgwfuncs-0.0.25.dist-info/entry_points.txt,sha256=j-c5IOPIQ0252EaOV6j6STio56sbXl2C4ym_fQ0lXx0,43
|
10
|
-
rgwfuncs-0.0.25.dist-info/top_level.txt,sha256=aGuVIzWsKiV1f2gCb6mynx0zx5ma0B1EwPGFKVEMTi4,9
|
11
|
-
rgwfuncs-0.0.25.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|