funcguard 0.2.53__tar.gz → 0.2.55__tar.gz
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.
- {funcguard-0.2.53 → funcguard-0.2.55}/PKG-INFO +5 -5
- {funcguard-0.2.53 → funcguard-0.2.55}/README.md +4 -4
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/__init__.py +1 -2
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/__init__.py +4 -3
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/convert_utils.py +131 -83
- funcguard-0.2.53/funcguard/pd_utils/fill_round.py → funcguard-0.2.55/funcguard/pd_utils/fill_utils.py +1 -30
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/time_utils.py +34 -33
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard.egg-info/PKG-INFO +5 -5
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard.egg-info/SOURCES.txt +1 -1
- {funcguard-0.2.53 → funcguard-0.2.55}/setup.py +1 -1
- {funcguard-0.2.53 → funcguard-0.2.55}/LICENSE +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/calculate.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/core.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/data_models/__init__.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/data_models/request_models.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/ip_utils.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/log_utils.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/date_utils.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/filter.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/json_utils/__init__.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/json_utils/json_parser.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/statistics/__init__.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/statistics/agg_utils.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/statistics/count_utils.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/statistics/df_statistics.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/pd_utils/statistics/mask_utils.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/printer.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard/tools.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard.egg-info/dependency_links.txt +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard.egg-info/not-zip-safe +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard.egg-info/requires.txt +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/funcguard.egg-info/top_level.txt +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/setup.cfg +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/tests/__init__.py +0 -0
- {funcguard-0.2.53 → funcguard-0.2.55}/tests/test_pd_filter_empty.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: funcguard
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.55
|
|
4
4
|
Summary: FuncGuard是一个Python库,提供函数执行超时控制、重试机制、HTTP请求封装和格式化打印工具。
|
|
5
5
|
Home-page: https://github.com/tinycen/funcguard
|
|
6
6
|
Author: tinycen
|
|
@@ -515,7 +515,7 @@ FuncGuard提供了丰富的pandas数据处理功能,包括数据填充、类
|
|
|
515
515
|
|
|
516
516
|
```python
|
|
517
517
|
import pandas as pd
|
|
518
|
-
from funcguard.pd_utils import fill_na, convert_columns,
|
|
518
|
+
from funcguard.pd_utils import fill_na, convert_columns, load_json
|
|
519
519
|
|
|
520
520
|
# 快速示例
|
|
521
521
|
df = pd.DataFrame({
|
|
@@ -589,8 +589,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
|
|
|
589
589
|
| `time_diff` | 耗时统计和计算 | [查看](docs/time_utils.md#time_diff) |
|
|
590
590
|
| `time_monitor` | 函数执行时间监控和警告 | [查看](docs/time_utils.md#time_monitor) |
|
|
591
591
|
| `time_wait` | 时间等待(带倒计时显示) | [查看](docs/time_utils.md#time_wait) |
|
|
592
|
-
| `get_now` |
|
|
593
|
-
| `generate_timestamp` | 生成时间戳 | - |
|
|
592
|
+
| `get_now` | 获取当前时间(支持多种格式输出) | - |
|
|
594
593
|
| `cal_date_diff` | 计算日期差异 | - |
|
|
595
594
|
|
|
596
595
|
### 打印工具
|
|
@@ -623,7 +622,8 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
|
|
|
623
622
|
| `pd_group_agg` | 分组聚合统计 | [查看](docs/pandas/agg.md) |
|
|
624
623
|
| `pd_build_mask` / `pd_build_masks` / `pd_combine_masks` | 掩码构建 | [查看](docs/pandas/mask.md) |
|
|
625
624
|
| `DataFrameStatistics` | 统计分析 | [查看](docs/pandas/statistics.md) |
|
|
626
|
-
| `pd_cal_date_diff`
|
|
625
|
+
| `pd_cal_date_diff` | 日期计算 | [查看](docs/pandas/date.md) |
|
|
626
|
+
| `pd_round_columns` | 数值舍入 | [查看](docs/pandas/convert.md) |
|
|
627
627
|
|
|
628
628
|
### 计算工具
|
|
629
629
|
|
|
@@ -483,7 +483,7 @@ FuncGuard提供了丰富的pandas数据处理功能,包括数据填充、类
|
|
|
483
483
|
|
|
484
484
|
```python
|
|
485
485
|
import pandas as pd
|
|
486
|
-
from funcguard.pd_utils import fill_na, convert_columns,
|
|
486
|
+
from funcguard.pd_utils import fill_na, convert_columns, load_json
|
|
487
487
|
|
|
488
488
|
# 快速示例
|
|
489
489
|
df = pd.DataFrame({
|
|
@@ -557,8 +557,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
|
|
|
557
557
|
| `time_diff` | 耗时统计和计算 | [查看](docs/time_utils.md#time_diff) |
|
|
558
558
|
| `time_monitor` | 函数执行时间监控和警告 | [查看](docs/time_utils.md#time_monitor) |
|
|
559
559
|
| `time_wait` | 时间等待(带倒计时显示) | [查看](docs/time_utils.md#time_wait) |
|
|
560
|
-
| `get_now` |
|
|
561
|
-
| `generate_timestamp` | 生成时间戳 | - |
|
|
560
|
+
| `get_now` | 获取当前时间(支持多种格式输出) | - |
|
|
562
561
|
| `cal_date_diff` | 计算日期差异 | - |
|
|
563
562
|
|
|
564
563
|
### 打印工具
|
|
@@ -591,7 +590,8 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
|
|
|
591
590
|
| `pd_group_agg` | 分组聚合统计 | [查看](docs/pandas/agg.md) |
|
|
592
591
|
| `pd_build_mask` / `pd_build_masks` / `pd_combine_masks` | 掩码构建 | [查看](docs/pandas/mask.md) |
|
|
593
592
|
| `DataFrameStatistics` | 统计分析 | [查看](docs/pandas/statistics.md) |
|
|
594
|
-
| `pd_cal_date_diff`
|
|
593
|
+
| `pd_cal_date_diff` | 日期计算 | [查看](docs/pandas/date.md) |
|
|
594
|
+
| `pd_round_columns` | 数值舍入 | [查看](docs/pandas/convert.md) |
|
|
595
595
|
|
|
596
596
|
### 计算工具
|
|
597
597
|
|
|
@@ -2,7 +2,7 @@ from .core import timeout_handler, retry_function, ask_select
|
|
|
2
2
|
from .tools import send_request, curl_cffi_request, check_url_valid, encode_basic_auth, md5_hash
|
|
3
3
|
from .time_utils import (
|
|
4
4
|
time_log, time_diff, time_monitor, time_wait, color_logger,
|
|
5
|
-
get_now,
|
|
5
|
+
get_now, cal_date_diff
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
from .printer import print_block, print_line, print_title, print_progress
|
|
@@ -68,7 +68,6 @@ __all__ = [
|
|
|
68
68
|
"setup_logger",
|
|
69
69
|
"color_logger",
|
|
70
70
|
"get_now",
|
|
71
|
-
"generate_timestamp",
|
|
72
71
|
"cal_date_diff",
|
|
73
72
|
|
|
74
73
|
# 打印工具
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
|
-
from .
|
|
2
|
+
from .fill_utils import fill_na
|
|
3
3
|
from .date_utils import fill_nat, cal_date_diff
|
|
4
4
|
from .convert_utils import (
|
|
5
5
|
convert_series,
|
|
@@ -8,7 +8,8 @@ from .convert_utils import (
|
|
|
8
8
|
convert_numeric_series,
|
|
9
9
|
load_json,
|
|
10
10
|
convert_str_datetime,
|
|
11
|
-
convert_datetime_str
|
|
11
|
+
convert_datetime_str,
|
|
12
|
+
round_columns
|
|
12
13
|
)
|
|
13
14
|
from .statistics import (
|
|
14
15
|
pd_build_mask,
|
|
@@ -29,7 +30,6 @@ __all__ = [
|
|
|
29
30
|
# 数据填充类
|
|
30
31
|
'fill_na',
|
|
31
32
|
'fill_nat',
|
|
32
|
-
'round_columns',
|
|
33
33
|
'cal_date_diff',
|
|
34
34
|
|
|
35
35
|
# 数据转换类
|
|
@@ -40,6 +40,7 @@ __all__ = [
|
|
|
40
40
|
'convert_str_datetime',
|
|
41
41
|
'convert_datetime_str',
|
|
42
42
|
'load_json',
|
|
43
|
+
'round_columns',
|
|
43
44
|
|
|
44
45
|
# 数据筛选类
|
|
45
46
|
"pd_filter",
|
|
@@ -10,6 +10,51 @@ from pandas import (
|
|
|
10
10
|
from .json_utils import json_loads
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
# 数据类型映射常量
|
|
14
|
+
TYPE_MAPPING = {
|
|
15
|
+
"int": Int64Dtype(),
|
|
16
|
+
"float": Float64Dtype(),
|
|
17
|
+
"str": StringDtype(),
|
|
18
|
+
"bool": BooleanDtype(),
|
|
19
|
+
"datetime": "datetime64[ns]", # datetime使用字符串形式
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def convert_columns(df: pd.DataFrame, columns: Dict[str, str], decimal_places: Optional[int] = None) -> pd.DataFrame:
|
|
24
|
+
"""
|
|
25
|
+
转换DataFrame中指定列的数据类型。
|
|
26
|
+
|
|
27
|
+
参数:
|
|
28
|
+
- df (pd.DataFrame):输入的DataFrame。
|
|
29
|
+
- columns (Dict[str, str]):
|
|
30
|
+
要转换类型的字典,键为列名,值为目标数据类型。
|
|
31
|
+
支持的数据类型:'int', 'float', 'str', 'bool', 'datetime'。
|
|
32
|
+
- decimal_places (int, optional):当转换为'float'类型时保留的小数位数,默认为None表示不限制
|
|
33
|
+
|
|
34
|
+
返回:
|
|
35
|
+
- pd.DataFrame:列类型转换后的DataFrame。
|
|
36
|
+
"""
|
|
37
|
+
for column, target_type in columns.items():
|
|
38
|
+
if column in df.columns and target_type in TYPE_MAPPING:
|
|
39
|
+
try:
|
|
40
|
+
if target_type == "datetime":
|
|
41
|
+
df[column] = pd.to_datetime(df[column], errors="coerce")
|
|
42
|
+
elif target_type == "float":
|
|
43
|
+
df[column] = df[column].astype(
|
|
44
|
+
TYPE_MAPPING[target_type]
|
|
45
|
+
) # pyright: ignore[reportArgumentType]
|
|
46
|
+
if decimal_places is not None:
|
|
47
|
+
df[column] = df[column].round(decimal_places)
|
|
48
|
+
else:
|
|
49
|
+
df[column] = df[column].astype(
|
|
50
|
+
TYPE_MAPPING[target_type]
|
|
51
|
+
) # pyright: ignore[reportArgumentType]
|
|
52
|
+
except (ValueError, TypeError):
|
|
53
|
+
# 如果转换失败,保持原类型
|
|
54
|
+
pass
|
|
55
|
+
return df
|
|
56
|
+
|
|
57
|
+
|
|
13
58
|
def convert_series(
|
|
14
59
|
data: pd.Series,
|
|
15
60
|
return_type: Literal["dict", "df", "series"] = "dict"
|
|
@@ -52,29 +97,20 @@ def convert_series(
|
|
|
52
97
|
return data
|
|
53
98
|
|
|
54
99
|
|
|
55
|
-
# 数据类型映射常量
|
|
56
|
-
TYPE_MAPPING = {
|
|
57
|
-
"int": Int64Dtype(),
|
|
58
|
-
"float": Float64Dtype(),
|
|
59
|
-
"str": StringDtype(),
|
|
60
|
-
"bool": BooleanDtype(),
|
|
61
|
-
"datetime": "datetime64[ns]", # datetime使用字符串形式
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
100
|
def convert_numeric_series(series: pd.Series, decimal_places: Optional[int] = None) -> pd.Series:
|
|
66
101
|
"""
|
|
67
102
|
将Series转换为数值类型,并自动检测应该使用 int 还是 float。
|
|
103
|
+
当 decimal_places == 0 时,round后自动转为Int64类型。
|
|
68
104
|
|
|
69
105
|
流程:
|
|
70
106
|
1. 先统一转换为 float64(确保所有值都是数值类型)
|
|
71
|
-
2.
|
|
72
|
-
3.
|
|
73
|
-
4.
|
|
107
|
+
2. 如果指定了decimal_places,先执行round操作
|
|
108
|
+
3. 当decimal_places为0时,round后自动转为Int64类型
|
|
109
|
+
4. 否则检测非空值中是否存在小数,没有小数则转换为Int64,否则保持float64
|
|
74
110
|
|
|
75
111
|
参数:
|
|
76
112
|
- series (pd.Series):输入的Series
|
|
77
|
-
- decimal_places (int, optional)
|
|
113
|
+
- decimal_places (int, optional):保留的小数位数,默认为None表示不限制
|
|
78
114
|
|
|
79
115
|
返回:
|
|
80
116
|
- pd.Series:转换后的Series
|
|
@@ -82,55 +118,87 @@ def convert_numeric_series(series: pd.Series, decimal_places: Optional[int] = No
|
|
|
82
118
|
# 先统一转换为 float
|
|
83
119
|
series = series.astype(float)
|
|
84
120
|
|
|
121
|
+
# 如果指定了decimal_places,先执行round操作
|
|
122
|
+
if decimal_places is not None:
|
|
123
|
+
series = series.round(decimal_places)
|
|
124
|
+
if decimal_places == 0:
|
|
125
|
+
# decimal_places为0时,round后自动转为Int64类型(支持NaN)
|
|
126
|
+
return series.astype("Int64")
|
|
127
|
+
|
|
85
128
|
# 检测是否存在小数
|
|
86
129
|
non_null_values = series.dropna()
|
|
87
130
|
if len(non_null_values) > 0:
|
|
88
131
|
# 检查是否有任何值有小数部分
|
|
89
132
|
has_decimal = any(non_null_values != non_null_values.round())
|
|
90
133
|
if not has_decimal:
|
|
91
|
-
# 没有小数,转换为
|
|
92
|
-
return series.astype("
|
|
134
|
+
# 没有小数,转换为 Int64(支持NaN),并返回Int64类型的Series
|
|
135
|
+
return series.astype("Int64")
|
|
93
136
|
|
|
94
137
|
# 有小数或全是空值,保持 float64
|
|
95
|
-
# 如果指定了decimal_places,对float类型执行round操作
|
|
96
|
-
if decimal_places is not None:
|
|
97
|
-
series = series.round(decimal_places)
|
|
98
|
-
|
|
99
138
|
return series
|
|
100
139
|
|
|
101
140
|
|
|
102
|
-
def
|
|
141
|
+
def _resolve_columns_decimal_places(
|
|
142
|
+
columns: Union[List[str], Dict[str, Optional[int]]],
|
|
143
|
+
decimal_places: Optional[int],
|
|
144
|
+
) -> tuple[List[str], Dict[str, Optional[int]]]:
|
|
103
145
|
"""
|
|
104
|
-
|
|
146
|
+
解析 columns 参数,返回目标列列表和每列对应的 decimal_places 字典。
|
|
147
|
+
|
|
148
|
+
参数:
|
|
149
|
+
- columns: 列名列表或字典
|
|
150
|
+
- decimal_places: 默认的 decimal_places 值
|
|
151
|
+
|
|
152
|
+
返回:
|
|
153
|
+
- target_columns: 目标列列表
|
|
154
|
+
- column_decimal_places: 每列对应的 decimal_places 字典
|
|
155
|
+
"""
|
|
156
|
+
if isinstance(columns, list):
|
|
157
|
+
target_columns = columns
|
|
158
|
+
column_decimal_places = {col: decimal_places for col in target_columns}
|
|
159
|
+
elif isinstance(columns, dict):
|
|
160
|
+
for col, val in columns.items():
|
|
161
|
+
if val is not None and not isinstance(val, int):
|
|
162
|
+
raise TypeError(
|
|
163
|
+
f"列 '{col}' 的 decimal_places 必须是整数或 None,得到 {type(val).__name__}"
|
|
164
|
+
)
|
|
165
|
+
target_columns = list(columns.keys())
|
|
166
|
+
column_decimal_places = {col: val for col, val in columns.items()}
|
|
167
|
+
else:
|
|
168
|
+
raise TypeError(
|
|
169
|
+
f"columns 参数类型不支持,期望 List[str] 或 Dict[str, Optional[int]],"
|
|
170
|
+
f"得到 {type(columns).__name__}"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
return target_columns, column_decimal_places
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def round_columns(
|
|
177
|
+
df: pd.DataFrame,
|
|
178
|
+
columns: Union[List[str], Dict[str, Optional[int]]],
|
|
179
|
+
decimal_places: int = 0,
|
|
180
|
+
) -> pd.DataFrame:
|
|
181
|
+
"""
|
|
182
|
+
对DataFrame中指定列进行四舍五入操作。
|
|
183
|
+
自动支持 Decimal 类型列和 NaN 值。
|
|
105
184
|
|
|
106
185
|
参数:
|
|
107
186
|
- df (pd.DataFrame):输入的DataFrame。
|
|
108
|
-
- columns (Dict[str,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- decimal_places (int, optional)
|
|
187
|
+
- columns (List[str], Dict[str, Optional[int]]):
|
|
188
|
+
* 如果为List[str],则对指定列进行四舍五入
|
|
189
|
+
* 如果为Dict[str, Optional[int]],则键为列名,值为该列的decimal_places(可选)
|
|
190
|
+
- decimal_places (int, optional):保留的小数位数,默认为0。
|
|
112
191
|
|
|
113
192
|
返回:
|
|
114
|
-
- pd.DataFrame
|
|
193
|
+
- pd.DataFrame:四舍五入后的DataFrame。
|
|
115
194
|
"""
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
TYPE_MAPPING[target_type]
|
|
124
|
-
) # pyright: ignore[reportArgumentType]
|
|
125
|
-
if decimal_places is not None:
|
|
126
|
-
df[column] = df[column].round(decimal_places)
|
|
127
|
-
else:
|
|
128
|
-
df[column] = df[column].astype(
|
|
129
|
-
TYPE_MAPPING[target_type]
|
|
130
|
-
) # pyright: ignore[reportArgumentType]
|
|
131
|
-
except (ValueError, TypeError):
|
|
132
|
-
# 如果转换失败,保持原类型
|
|
133
|
-
pass
|
|
195
|
+
target_columns, column_decimal_places = _resolve_columns_decimal_places(
|
|
196
|
+
columns, decimal_places
|
|
197
|
+
)
|
|
198
|
+
for column in target_columns:
|
|
199
|
+
if column in df.columns:
|
|
200
|
+
col_dp = column_decimal_places.get(column, decimal_places)
|
|
201
|
+
df[column] = convert_numeric_series(df[column], col_dp)
|
|
134
202
|
return df
|
|
135
203
|
|
|
136
204
|
|
|
@@ -144,23 +212,22 @@ def _has_decimal(df: pd.DataFrame, column: str) -> bool:
|
|
|
144
212
|
|
|
145
213
|
def convert_decimal(
|
|
146
214
|
df: pd.DataFrame,
|
|
147
|
-
columns: Union[List[str], Dict[str,
|
|
148
|
-
target_type: str = "int",
|
|
215
|
+
columns: Union[List[str], Dict[str, Optional[int]], None] = None,
|
|
149
216
|
decimal_places: Optional[int] = None,
|
|
150
217
|
) -> pd.DataFrame:
|
|
151
218
|
"""
|
|
152
|
-
检测DataFrame中是否包含Decimal
|
|
219
|
+
检测DataFrame中是否包含Decimal类型的字段,如果包含则转换为数值类型。
|
|
220
|
+
自动检测:先转为float,如果没有小数则转为int,否则保持float。
|
|
221
|
+
当 decimal_places == 0 时,round后自动转为Int64类型。
|
|
153
222
|
|
|
154
223
|
参数:
|
|
155
224
|
- df (pd.DataFrame):输入的DataFrame。
|
|
156
|
-
- columns (List[str], Dict[str,
|
|
225
|
+
- columns (List[str], Dict[str, Optional[int]], or None):
|
|
157
226
|
* 如果为None,则检测所有列
|
|
158
|
-
* 如果为List[str]
|
|
159
|
-
* 如果为Dict[str,
|
|
160
|
-
-
|
|
161
|
-
|
|
162
|
-
'auto'表示自动检测:先转为float,如果没有小数则转为int。
|
|
163
|
-
- decimal_places (int, optional):当target_type为'auto'或'float'时,保留的小数位数,默认为None表示不限制
|
|
227
|
+
* 如果为List[str],则检测指定列
|
|
228
|
+
* 如果为Dict[str, Optional[int]],则键为列名,值为该列的decimal_places(可选)
|
|
229
|
+
- decimal_places (int, optional):保留的小数位数,默认为None表示不限制。
|
|
230
|
+
当decimal_places为0时,round后自动转为Int64类型。
|
|
164
231
|
|
|
165
232
|
返回:
|
|
166
233
|
- pd.DataFrame:转换后的DataFrame。
|
|
@@ -168,23 +235,11 @@ def convert_decimal(
|
|
|
168
235
|
if columns is None:
|
|
169
236
|
# 检测所有列
|
|
170
237
|
target_columns = df.columns.tolist()
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
elif isinstance(columns, dict):
|
|
177
|
-
# 使用字典指定的类型
|
|
178
|
-
target_columns = list(columns.keys())
|
|
179
|
-
column_types = columns
|
|
180
|
-
|
|
181
|
-
# 验证target_type和字典中的类型是否有效
|
|
182
|
-
valid_types = {"int", "float", "auto"}
|
|
183
|
-
for col, target_type in column_types.items():
|
|
184
|
-
if target_type not in valid_types:
|
|
185
|
-
raise ValueError(
|
|
186
|
-
f"无效的类型指定:{target_type}。支持的类型为:{valid_types}"
|
|
187
|
-
)
|
|
238
|
+
column_decimal_places = {col: decimal_places for col in target_columns}
|
|
239
|
+
else:
|
|
240
|
+
target_columns, column_decimal_places = _resolve_columns_decimal_places(
|
|
241
|
+
columns, decimal_places
|
|
242
|
+
)
|
|
188
243
|
|
|
189
244
|
for column in target_columns:
|
|
190
245
|
# 检查列是否存在且为object类型 (只有object类型列才可能包含Decimal)
|
|
@@ -192,16 +247,8 @@ def convert_decimal(
|
|
|
192
247
|
continue
|
|
193
248
|
# 检查列中是否存在 Decimal 类型值
|
|
194
249
|
if _has_decimal(df, column):
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if col_target_type == "int":
|
|
198
|
-
df[column] = df[column].astype(int)
|
|
199
|
-
elif col_target_type == "float":
|
|
200
|
-
df[column] = df[column].astype(float)
|
|
201
|
-
if decimal_places is not None:
|
|
202
|
-
df[column] = df[column].round(decimal_places)
|
|
203
|
-
elif col_target_type == "auto":
|
|
204
|
-
df[column] = convert_numeric_series(df[column], decimal_places)
|
|
250
|
+
col_dp = column_decimal_places.get(column, decimal_places)
|
|
251
|
+
df[column] = convert_numeric_series(df[column], col_dp)
|
|
205
252
|
|
|
206
253
|
return df
|
|
207
254
|
|
|
@@ -296,4 +343,5 @@ def convert_str_datetime(
|
|
|
296
343
|
|
|
297
344
|
df[column] = df[column].apply(parse_datetime)
|
|
298
345
|
|
|
299
|
-
return df
|
|
346
|
+
return df
|
|
347
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
|
-
from pandas.api.types import is_datetime64_any_dtype, is_timedelta64_dtype
|
|
2
|
+
from pandas.api.types import is_datetime64_any_dtype, is_timedelta64_dtype
|
|
3
3
|
from typing import Union, List, Any, Dict, Optional
|
|
4
4
|
from .convert_utils import convert_numeric_series
|
|
5
5
|
|
|
@@ -64,32 +64,3 @@ def fill_na(
|
|
|
64
64
|
column_dtype = df[column].dtype
|
|
65
65
|
raise TypeError(f"处理列 '{column}' (类型: {column_dtype}) 时出错: {e}") from e
|
|
66
66
|
return df
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def round_columns(
|
|
70
|
-
df: pd.DataFrame, columns: List[str], decimal_places: int = 0
|
|
71
|
-
) -> pd.DataFrame:
|
|
72
|
-
"""
|
|
73
|
-
对DataFrame中指定列进行四舍五入操作。
|
|
74
|
-
|
|
75
|
-
参数:
|
|
76
|
-
- df (pd.DataFrame):输入的DataFrame。
|
|
77
|
-
- columns (List[str]):要进行四舍五入的列名列表。
|
|
78
|
-
- decimal_places (int, optional):保留的小数位数,默认为0。
|
|
79
|
-
|
|
80
|
-
返回:
|
|
81
|
-
- pd.DataFrame:四舍五入后的DataFrame。
|
|
82
|
-
|
|
83
|
-
注意:
|
|
84
|
-
- 当 decimal_places 为 0 时,结果列会自动转换为 Int64(可空整数)类型。
|
|
85
|
-
- decimal.Decimal 类型在 pandas 中以 object dtype 存储,不被视为数值类型,
|
|
86
|
-
调用本函数会抛出 TypeError。需先手动将其转换为 float 类型再调用本函数。
|
|
87
|
-
"""
|
|
88
|
-
for column in columns:
|
|
89
|
-
if column in df.columns:
|
|
90
|
-
if not is_numeric_dtype(df[column]):
|
|
91
|
-
raise TypeError(f"列 '{column}' 不是数值类型,无法执行四舍五入操作")
|
|
92
|
-
df[column] = df[column].round(decimal_places)
|
|
93
|
-
if decimal_places == 0:
|
|
94
|
-
df[column] = df[column].astype('Int64')
|
|
95
|
-
return df
|
|
@@ -177,61 +177,62 @@ def time_monitor(warning_threshold=None, print_mode=2, func=None, *args, **kwarg
|
|
|
177
177
|
|
|
178
178
|
|
|
179
179
|
# 获取当前的时间
|
|
180
|
-
def get_now( from_timezone = "local", remove_tzinfo = True ):
|
|
180
|
+
def get_now( from_timezone = "local", remove_tzinfo = True, fmt = None ):
|
|
181
|
+
"""
|
|
182
|
+
获取当前时间,支持多种时区和输出格式。
|
|
183
|
+
|
|
184
|
+
:param from_timezone: 时区选择:
|
|
185
|
+
- "local": 本地时间(tz-naive,不含时区信息)。
|
|
186
|
+
- "utc": UTC时间(tz-aware,包含 UTC 时区信息)。
|
|
187
|
+
- "bj": 北京时间(tz-aware,包含 UTC+8 时区信息)。
|
|
188
|
+
|
|
189
|
+
naive vs aware 的区别:
|
|
190
|
+
- naive(无时区信息):仅表示一个日期和时间,不知道自己处于哪个时区,其含义取决于运行环境。
|
|
191
|
+
- aware(有时区信息):包含时区信息,能够准确定位自己在绝对时间轴上的位置。
|
|
192
|
+
- naive 和 aware 不能直接进行比较/计算,因为 naive 对象没有时区信息,无法确定其在时间轴上的具体位置。
|
|
193
|
+
|
|
194
|
+
:param remove_tzinfo: 是否移除时区信息,默认为 True(仅 fmt=None 时生效,影响返回的 datetime 对象)
|
|
195
|
+
:param fmt: 输出格式,默认为 None(返回 datetime 对象):
|
|
196
|
+
- None: 返回 datetime 对象
|
|
197
|
+
- "millis": 返回毫秒级时间戳(int)
|
|
198
|
+
- "iso": 返回 ISO 8601 格式字符串,例如 2024-03-15T14:00:00;当 from_timezone="utc" 时自动追加 Z 后缀(Z = Zulu time = UTC+0)
|
|
199
|
+
- "str": 返回普通字符串,格式为 %Y-%m-%d %H:%M:%S
|
|
200
|
+
:return: datetime 对象 | int(毫秒时间戳) | str(格式化字符串)
|
|
201
|
+
"""
|
|
181
202
|
if from_timezone == "local" :
|
|
182
203
|
now_time = datetime.now() # 获取当前本地时间 (tz-naive) ,不包含时区信息
|
|
183
204
|
|
|
184
205
|
elif from_timezone == "utc" :
|
|
185
206
|
now_time = datetime.now( timezone.utc ) # 获取当前UTC时间 (tz-aware) ,包含时区信息
|
|
186
207
|
|
|
187
|
-
elif from_timezone == "
|
|
208
|
+
elif from_timezone == "bj" : # 固定北京时间 (tz-aware) ,包含时区信息
|
|
188
209
|
now_time = datetime.now( timezone( timedelta( hours = 8 ) ) )
|
|
189
210
|
|
|
190
|
-
else :
|
|
191
|
-
raise ValueError( "Invalid timezone , must be 'local' , 'utc' , '
|
|
192
|
-
|
|
193
|
-
if remove_tzinfo:
|
|
194
|
-
return now_time.replace( tzinfo = None )
|
|
195
|
-
|
|
196
|
-
return now_time
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
# 获取时间戳
|
|
200
|
-
def generate_timestamp( from_timezone = "local", fmt = "millis", utc_z = False ) :
|
|
201
|
-
"""
|
|
202
|
-
获取当前时间戳或格式化时间字符串
|
|
203
|
-
|
|
204
|
-
:param from_timezone: 时区选择,决定返回的时间对象类型:
|
|
205
|
-
- "local": 返回本地时间的 naive 对象(不含时区信息)。
|
|
206
|
-
- "utc": 返回 UTC 时间的 aware 对象(包含 UTC 时区信息)。
|
|
207
|
-
- "beijing": 返回北京时间的 aware 对象(包含 UTC+8 时区信息)。
|
|
208
|
-
|
|
209
|
-
naive vs aware 的区别:
|
|
210
|
-
- naive (无时区信息):不包含时区信息的对象。它仅表示一个日期和时间,但不知道自己处于哪个时区。其含义取决于运行环境。
|
|
211
|
-
- aware (有时区信息):包含时区信息的对象。它能够准确地定位自己在绝对时间轴上的位置。
|
|
212
|
-
- naive 和 aware 不能直接进行比较/计算,因为 naive 对象没有时区信息,无法确定其在时间轴上的具体位置。
|
|
211
|
+
else :
|
|
212
|
+
raise ValueError( "Invalid timezone , must be 'local' , 'utc' , 'bj' " )
|
|
213
213
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
214
|
+
# 未指定 fmt 时,返回 datetime 对象
|
|
215
|
+
if fmt is None :
|
|
216
|
+
if remove_tzinfo :
|
|
217
|
+
return now_time.replace( tzinfo = None )
|
|
218
|
+
return now_time
|
|
218
219
|
|
|
219
|
-
# 格式化为ISO 8601
|
|
220
|
+
# 格式化为 ISO 8601 标准格式(UTC 时区自动追加 Z 后缀)
|
|
220
221
|
if fmt == "iso" :
|
|
221
|
-
if from_timezone == "utc"
|
|
222
|
+
if from_timezone == "utc" :
|
|
222
223
|
return now_time.strftime( '%Y-%m-%dT%H:%M:%SZ' )
|
|
223
|
-
|
|
224
224
|
return now_time.strftime( '%Y-%m-%dT%H:%M:%S' )
|
|
225
225
|
|
|
226
226
|
# 转换为毫秒级时间戳
|
|
227
227
|
elif fmt == "millis" :
|
|
228
228
|
return int( now_time.timestamp() * 1000 )
|
|
229
229
|
|
|
230
|
+
# 格式化为普通字符串
|
|
230
231
|
elif fmt == "str" :
|
|
231
232
|
return now_time.strftime( '%Y-%m-%d %H:%M:%S' )
|
|
232
233
|
|
|
233
234
|
else :
|
|
234
|
-
raise ValueError( "Invalid fmt , must be 'millis' , 'iso' or 'str'" )
|
|
235
|
+
raise ValueError( "Invalid fmt , must be None , 'millis' , 'iso' or 'str'" )
|
|
235
236
|
|
|
236
237
|
|
|
237
238
|
# 计算日期差值
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: funcguard
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.55
|
|
4
4
|
Summary: FuncGuard是一个Python库,提供函数执行超时控制、重试机制、HTTP请求封装和格式化打印工具。
|
|
5
5
|
Home-page: https://github.com/tinycen/funcguard
|
|
6
6
|
Author: tinycen
|
|
@@ -515,7 +515,7 @@ FuncGuard提供了丰富的pandas数据处理功能,包括数据填充、类
|
|
|
515
515
|
|
|
516
516
|
```python
|
|
517
517
|
import pandas as pd
|
|
518
|
-
from funcguard.pd_utils import fill_na, convert_columns,
|
|
518
|
+
from funcguard.pd_utils import fill_na, convert_columns, load_json
|
|
519
519
|
|
|
520
520
|
# 快速示例
|
|
521
521
|
df = pd.DataFrame({
|
|
@@ -589,8 +589,7 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
|
|
|
589
589
|
| `time_diff` | 耗时统计和计算 | [查看](docs/time_utils.md#time_diff) |
|
|
590
590
|
| `time_monitor` | 函数执行时间监控和警告 | [查看](docs/time_utils.md#time_monitor) |
|
|
591
591
|
| `time_wait` | 时间等待(带倒计时显示) | [查看](docs/time_utils.md#time_wait) |
|
|
592
|
-
| `get_now` |
|
|
593
|
-
| `generate_timestamp` | 生成时间戳 | - |
|
|
592
|
+
| `get_now` | 获取当前时间(支持多种格式输出) | - |
|
|
594
593
|
| `cal_date_diff` | 计算日期差异 | - |
|
|
595
594
|
|
|
596
595
|
### 打印工具
|
|
@@ -623,7 +622,8 @@ print(f"当前价格: {current_price}, 变化: {price_change}") # 输出: 当
|
|
|
623
622
|
| `pd_group_agg` | 分组聚合统计 | [查看](docs/pandas/agg.md) |
|
|
624
623
|
| `pd_build_mask` / `pd_build_masks` / `pd_combine_masks` | 掩码构建 | [查看](docs/pandas/mask.md) |
|
|
625
624
|
| `DataFrameStatistics` | 统计分析 | [查看](docs/pandas/statistics.md) |
|
|
626
|
-
| `pd_cal_date_diff`
|
|
625
|
+
| `pd_cal_date_diff` | 日期计算 | [查看](docs/pandas/date.md) |
|
|
626
|
+
| `pd_round_columns` | 数值舍入 | [查看](docs/pandas/convert.md) |
|
|
627
627
|
|
|
628
628
|
### 计算工具
|
|
629
629
|
|
|
@@ -20,7 +20,7 @@ funcguard/data_models/request_models.py
|
|
|
20
20
|
funcguard/pd_utils/__init__.py
|
|
21
21
|
funcguard/pd_utils/convert_utils.py
|
|
22
22
|
funcguard/pd_utils/date_utils.py
|
|
23
|
-
funcguard/pd_utils/
|
|
23
|
+
funcguard/pd_utils/fill_utils.py
|
|
24
24
|
funcguard/pd_utils/filter.py
|
|
25
25
|
funcguard/pd_utils/json_utils/__init__.py
|
|
26
26
|
funcguard/pd_utils/json_utils/json_parser.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|