活动介绍

pd.to_datetime(data['出版时间'], format=df)u'y'

时间: 2023-09-17 13:12:05 浏览: 228
这句代码的作用是将一个名为 `data` 的 pandas DataFrame 中的名为 `出版时间` 的列转换为日期格式,并且使用 `df` 变量中定义的格式化字符串来解析日期字符串。 具体解释如下: 1. `data['出版时间']` 表示选取 `data` DataFrame 中的名为 `出版时间` 的列。 2. `format=df` 表示使用变量 `df` 中定义的格式化字符串来解析日期字符串。`df` 应该是一个字符串,例如 `%Y-%m-%d`,用于指定日期字符串中各部分的顺序和格式。在这里,`y` 不是有效的格式字符,所以如果在 `df` 中有一个错误的格式字符,那么代码就会失败。 3. `pd.to_datetime()` 函数将 `data['出版时间']` 中的日期字符串序列转换为日期格式序列,并返回一个新的 pandas Series。这个新的 Series 可以直接赋值给原始 DataFrame 中的 `出版时间` 列,也可以作为新的一列添加到 DataFrame 中。 总之,这句代码的作用是将一个数据框中的某一列日期字符串转换为日期格式,并且使用自定义格式化字符串来解析日期字符串。
相关问题

c:\users\1\desktop\未命名1.py:52: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format. source_time = pd.to_datetime(main_damage_df.iloc[:, 0]) Traceback (most recent call last): File D:\anaconda3\Lib\site-packages\spyder_kernels\py3compat.py:356 in compat_exec exec(code, globals, locals) File c:\users\1\desktop\未命名1.py:81 main_damage, tower_damage = load_and_align_damage_data(damage_file, n_turbines, target_time) File c:\users\1\desktop\未命名1.py:52 in load_and_align_damage_data source_time = pd.to_datetime(main_damage_df.iloc[:, 0]) File D:\anaconda3\Lib\site-packages\pandas\core\tools\datetimes.py:1067 in to_datetime values = convert_listlike(arg._values, format) File D:\anaconda3\Lib\site-packages\pandas\core\tools\datetimes.py:435 in _convert_listlike_datetimes result, tz_parsed = objects_to_datetime64( File D:\anaconda3\Lib\site-packages\pandas\core\arrays\datetimes.py:2398 in objects_to_datetime64 result, tz_parsed = tslib.array_to_datetime( File tslib.pyx:414 in pandas._libs.tslib.array_to_datetime File tslib.pyx:596 in pandas._libs.tslib.array_to_datetime File tslib.pyx:553 in pandas._libs.tslib.array_to_datetime File conversion.pyx:641 in pandas._libs.tslibs.conversion.convert_str_to_tsobject File parsing.pyx:336 in pandas._libs.tslibs.parsing.parse_datetime_string File parsing.pyx:666 in pandas._libs.tslibs.parsing.dateutil_parse DateParseError: Unknown datetime string format, unable to parse: 时间(s), at position 0

<think>好的,用户遇到了一个关于解析时间字符串的错误。首先,我需要仔细阅读用户提供的错误信息。错误提示显示在调用`pd.to_datetime`时,pandas无法推断出时间格式,导致解析失败。具体来说,错误发生在`main_damage_df.iloc[:, 0]`的第0行,内容可能是“时间(s)”这样的字符串,而不是实际的时间数据。 接下来,用户提到他们正在处理没有表头的Excel文件,这可能意味着数据的第一行是列名,比如“时间(s)”,而后续行才是实际的时间戳。然而,在之前的代码修改中,用户已经将`header=None`传递给`pd.read_excel`,这会导致pandas将第一行数据视为普通数据而非表头。因此,当尝试解析第一列的时间数据时,pandas可能错误地读取了列名“时间(s)”作为时间戳,从而引发解析错误。 为了解决这个问题,需要确保在读取无表头的Excel文件时,正确识别时间列。可能的解决方案包括: 1. **检查数据起始行**:确认数据是否从第二行开始,因为第一行可能是列名。如果用户的数据确实没有表头,但第一行包含列名,可能需要调整代码,跳过第一行或正确指定数据起始行。 2. **指定时间格式**:在`pd.to_datetime`中显式指定时间格式,帮助pandas正确解析时间字符串。例如,如果时间戳的格式是“YYYY-MM-DD HH:MM:SS”,则使用`format='%Y-%m-%d %H:%M:%S'`参数。 3. **处理异常值**:检查数据中的异常值或非时间字符串,确保所有时间数据都符合预期格式。如果存在“时间(s)”这样的文本,可能需要在读取数据后删除或跳过该行。 4. **调试数据读取**:在代码中添加调试语句,打印出读取的DataFrame的前几行,确认数据是否正确加载,特别是时间列的内容。 根据用户的代码,`load_and_align_damage_data`函数中读取`main_damage_df`时使用了`header=None`,这意味着所有行都被视为数据行,包括可能的列名。如果原始数据中的第一行确实是列名(例如“时间(s)”),那么这些列名会被包含在数据中,导致解析时间时出现错误。因此,正确的做法应该是读取数据时跳过第一行,或者在读取后删除第一行。 此外,用户可能在附件5-问题一答案表.xlsx中存在表头行,但代码中使用了`header=None`,导致表头被当作数据处理。需要确认该文件的结构,是否确实没有表头,或者是否需要调整参数以正确读取表头。 总结解决步骤: - 确认`main_damage_df`和`tower_damage_df`的数据结构,检查是否有表头行。 - 如果存在表头行,调整`pd.read_excel`的参数,使用`header=0`来正确读取表头,并跳过第一行数据。 - 如果数据确实没有表头,但第一行包含列名,可能需要手动处理,例如读取后删除第一行。 - 在`pd.to_datetime`中指定明确的时间格式,避免自动推断失败。 最后,向用户提供修改后的代码示例,并解释每个改动的原因,确保他们理解如何处理类似的问题。 </think>```python # 修改后的损伤数据加载函数(处理无表头和时间格式问题) def load_and_align_damage_data(damage_file, n_turbines, target_time): # 读取时指定没有表头,并跳过第一行(假设第一行是列名"时间(s)") main_damage_df = pd.read_excel(damage_file, sheet_name='MainShaft', header=None, skiprows=1) tower_damage_df = pd.read_excel(damage_file, sheet_name='Tower', header=None, skiprows=1) # 显式指定时间格式(假设格式为"YYYY-MM-DD HH:MM:SS") source_time = pd.to_datetime(main_damage_df.iloc[:, 0], format='%Y-%m-%d %H:%M:%S') aligned_main = [] aligned_tower = [] for i in range(n_turbines): # 提取原始损伤数据(从第2列开始) source_main = main_damage_df.iloc[:, i+1].values source_tower = tower_damage_df.iloc[:, i+1].values # 插值对齐到目标时间 f_main = interp1d(source_time.astype(np.int64), source_main, kind='linear', fill_value='extrapolate') f_tower = interp1d(source_time.astype(np.int64), source_tower, kind='linear', fill_value='extrapolate') aligned_main.append(f_main(target_time.astype(np.int64))) aligned_tower.append(f_tower(target_time.astype(np.int64))) return np.array(aligned_main).T, np.array(aligned_tower).T ```

df_head = pd.read_csv(wind_file, nrows=1) df_data = pd.read_csv(wind_file, skiprows=1) df_data['Time and Date'] = pd.to_datetime(df_data['Time and Date']) df_filterd = df_data[(df_data['Time and Date']>=st) & (df_data['Time and Date']<=et)] df_res = pd.concat([df_head, df_filterd]) 将df_head 先写入csv的第一行,然后将df_filterd从csv的第二行开始写入

<think>好的,我现在需要解决用户的问题:如何将df_head写入CSV的第一行,然后从第二行开始写入df_filterd。用户提供的代码似乎已经做了一些操作,但可能没有正确实现这个目标。让我仔细分析一下。 首先,用户现有的代码是这样的: df_head = pd.read_csv(wind_file, nrows=1) df_data = pd.read_csv(wind_file, skiprows=1) df_data['Time and Date'] = pd.to_datetime(df_data['Time and Date']) df_filterd = df_data[(df_data['Time and Date']>=st) & (df_data['Time and Date']<=et)] df_res = pd.concat([df_head, df_filterd]) 然后用户希望将df_head作为CSV的第一行,df_filterd从第二行开始写入。看起来用户使用pd.concat将两者合并成df_res,之后可能需要将df_res写入CSV。但这里可能存在一个问题:当使用pd.concat时,如果两个DataFrame的列不完全一致,或者索引有问题,可能会导致写入CSV时出现意外的结果,比如重复的列名或索引被写入文件。 首先,我需要确认df_head的结构。用户用pd.read_csv读取nrows=1,这应该得到的是一个只有一行的DataFrame,包含CSV的列名和数据的第一行。但通常,CSV的第一行是列名,所以正确的做法可能是先读取列名,然后处理数据部分。不过用户可能已经处理好了,比如wind_file的第一行确实是数据,而列名可能在其他地方,或者用户希望保留原来的结构。这里可能需要进一步考虑,但根据用户的代码,他们可能已经将df_head作为标题行处理。 接下来,用户使用pd.concat合并df_head和df_filterd。但df_head是单独读取的第一行,而df_filterd是过滤后的数据,跳过了第一行。这里可能存在的问题是,当合并时,df_head可能包含原来的数据行,而df_filterd可能没有列名,导致合并后的DataFrame结构混乱。或者,可能df_head实际上是列名,但用户用nrows=1读取导致列名成为数据行,这可能需要检查。 可能的错误点在于,通常CSV的第一行是列名,但用户可能将第一行作为数据读取到df_head,然后跳过了第一行读取df_data,这样df_data的列名可能被设置为默认的列名(如Unnamed: 0等),因为第一行被跳过了,导致后续处理出错。因此,正确的做法应该是读取列名,然后处理数据,确保列名正确。 假设用户的情况是,wind_file的第一行是列名,那么正确的处理方式应该是: 1. 读取列名:使用pd.read_csv(wind_file, nrows=0)获取列名,或者读取第一行作为列名。 2. 读取数据部分,跳过第一行(如果第一行是列名的话),但用户原来的代码是读取第一行到df_head,然后跳过第一行读取df_data,这可能意味着wind_file的第一行是数据,而列名可能不存在,或者用户希望保留原来的结构。 这里可能存在误解,需要进一步分析。例如,如果wind_file的第一行是列名,那么正确的做法应该是: df_header = pd.read_csv(wind_file, nrows=0) # 获取列名 df_data = pd.read_csv(wind_file, skiprows=1) # 跳过列名行读取数据 但用户的做法是读取第一行到df_head,这可能意味着用户希望将第一行作为数据的一部分处理。例如,可能wind_file没有列名,第一行就是数据,而用户想要保留这一行作为标题或其他用途。这时候,当用户使用pd.concat([df_head, df_filterd])合并时,可能会将df_head作为数据行,然后写入到CSV中,第一行是原来的第一行数据,接着是过滤后的数据。 但用户的目标是将df_head写入CSV的第一行,df_filterd从第二行开始。所以可能需要确保在写入时,列名不被重复写入。例如,当使用to_csv时,是否包含header参数。例如,默认情况下,to_csv会写入列名作为第一行,但如果用户已经将df_head作为第一行数据,那么写入时需要设置header=False,避免重复的列名。 因此,用户可能的问题在于,当使用pd.concat合并df_head和df_filterd后,写入CSV时,pandas会自动添加列名,导致第一行是列名,第二行是df_head的数据,第三行开始是df_filterd的数据。但用户的意图是将df_head作为第一行数据,df_filterd作为后续数据,而不需要额外的列名行。 因此,正确的步骤应该是: 1. 将df_head和df_filterd合并为一个DataFrame。 2. 写入到CSV时,不包含列名(header=False),这样第一行就是df_head的数据,后面是df_filterd的数据。 但这样可能存在的问题是,原来的列名可能丢失。如果wind_file原本没有列名,或者用户希望保留原有的结构,这可能可行。但如果原来的CSV有列名,而df_head是数据行,那么用户可能需要确保在写入时,列名不被写入,而数据正确。 或者,用户可能误将列名作为数据行处理,导致后续的问题。因此,需要确认如何处理列名。 回到用户当前的代码: df_head = pd.read_csv(wind_file, nrows=1) # 读取第一行作为数据,假设没有列名,或者列名在第一行 df_data = pd.read_csv(wind_file, skiprows=1) # 跳过第一行读取数据,此时如果第一行是列名,那么df_data的列名会被正确设置;否则,列名会是默认的0,1,2... 如果wind_file原本有列名,那么用户的代码会导致df_head读取列名作为数据行,而df_data跳过了列名行,导致数据读取错误。这时候,正确的做法应该是: df_data = pd.read_csv(wind_file, skiprows=1, header=None) # 如果没有列名,跳过第一行数据,并且不读取列名 但用户可能的情况是,wind_file的第一行是数据,没有列名,因此需要保留df_head作为第一行,然后过滤后的数据作为后续行。 假设用户的情况是,CSV文件没有列名,第一行就是数据,那么用户的代码是正确的。此时,df_head是第一行数据,df_data是剩余的数据(跳过第一行)。然后,处理后的df_filterd需要和df_head合并,然后写入到CSV,其中第一行是df_head,后面是df_filterd。 但用户的问题是,如何将df_head写入CSV的第一行,df_filterd从第二行开始。这时候,使用pd.concat([df_head, df_filterd])得到df_res,然后使用df_res.to_csv('output.csv', index=False, header=False)可能可以实现,因为这样不会写入列名,只写入数据行。但需要确认df_head和df_filterd的结构是否一致,即列数相同,列名可能不需要,或者已经被处理。 但用户原来的代码可能存在的问题是,当使用pd.concat时,如果df_head和df_filterd的列名不一致,可能会导致合并后的DataFrame列对齐错误。例如,如果df_head是读取的第一行数据(没有列名,可能列名是0,1,2...),而df_data在读取时可能因为skiprows=1导致列名也是0,1,2...,因此df_filterd的列名与df_head一致,所以concat没有问题。 不过,在写入时,如果用户直接使用df_res.to_csv('output.csv', index=False),则会将列名作为第一行写入,这可能导致输出文件的第一行是列名(如0,1,2...),然后第二行是df_head的数据,第三行开始是df_filterd的数据,这不是用户想要的。因此,用户需要确保在写入时不包含列名,即设置header=False。 因此,正确的写入方式应该是: df_res.to_csv('output.csv', index=False, header=False) 这样,第一行就是df_head的数据,之后是df_filterd的数据。 总结用户的代码可能的错误: 1. 在合并df_head和df_filterd时,可能需要确保列对齐。 2. 写入CSV时没有正确设置header参数,导致额外的列名行。 因此,修改后的步骤应该是: 1. 确保df_head和df_filterd的列名一致,或者忽略列名,直接按顺序合并。 2. 使用to_csv时设置header=False,避免写入列名。 此外,用户需要注意,当读取df_head时,是否应该保留列名。如果原CSV文件有列名,而用户希望保留,那么当前的读取方式可能错误,应该先读取列名,再读取数据。 假设原CSV没有列名,用户希望第一行是数据,那么当前的方法是正确的,但写入时需要关闭header。 另外,用户代码中的df_res = pd.concat([df_head, df_filterd])可能存在索引问题,因为两个DataFrame可能有重叠的索引,导致concat后的索引不连续。但写入CSV时使用index=False可以忽略这个问题。 可能的改进步骤: - 确保df_head和df_filterd的列对齐。 - 合并时使用ignore_index=True,重置索引。 - 写入时禁用header和index。 例如: df_res = pd.concat([df_head, df_filterd], ignore_index=True) df_res.to_csv('output.csv', index=False, header=False) 但需要确认列是否对齐。 另一个可能性是,用户可能希望保留原来的列名,这时候需要确保df_head包含列名。例如,如果wind_file的第一行是列名,那么df_head应该读取列名,然后df_data跳过第一行数据。但用户当前的代码可能没有正确处理这种情况。 例如,正确的处理方式应该是: 如果CSV有列名: df_columns = pd.read_csv(wind_file, nrows=0).columns.tolist() df_data = pd.read_csv(wind_file, skiprows=1, header=None) df_data.columns = df_columns 但用户可能的情况不同。 总之,用户的目标是将df_head作为第一行数据,df_filterd作为后续数据写入CSV,可能需要: 1. 合并df_head和df_filterd。 2. 写入时禁用列名和索引。 因此,正确的代码应该是: df_res = pd.concat([df_head, df_filterd], ignore_index=True) df_res.to_csv('output.csv', index=False, header=False) 这样应该就能实现用户的需求。</think>要將 `df_head` 寫入 CSV 的第一行,並將 `df_filterd` 從第二行開始寫入,可以按照以下步驟操作: --- ### **1. 代碼分析與問題定位** 你的原始代碼邏輯如下: ```python df_head = pd.read_csv(wind_file, nrows=1) # 讀取 CSV 的第一行(假設為標題或首行數據) df_data = pd.read_csv(wind_file, skiprows=1) # 跳過第一行,讀取剩餘數據 # 過濾時間範圍內的數據 df_data['Time and Date'] = pd.to_datetime(df_data['Time and Date']) df_filterd = df_data[(df_data['Time and Date']>=st) & (df_data['Time and Date']<=et)] # 合併 df_head 和 df_filterd df_res = pd.concat([df_head, df_filterd]) ``` #### **潛在問題** - **列名衝突**:`df_head` 和 `df_filterd` 可能包含不同的列名,導致合併時數據錯位。 - **索引問題**:直接合併可能保留原始索引,寫入 CSV 時產生多餘的索引列。 - **標題行重複**:若 `df_head` 是標題行,直接合併後寫入 CSV 時可能導致標題重複。 --- ### **2. 解決方案:確保列名一致並正確寫入** #### **步驟 1:統一列名** 確保 `df_head` 和 `df_filterd` 的列名一致: ```python # 提取 df_head 的列名 columns = df_head.columns.tolist() # 將列名賦值給 df_filterd df_filterd.columns = columns ``` #### **步驟 2:合併數據並重置索引** ```python # 合併並忽略原始索引 df_res = pd.concat([df_head, df_filterd], ignore_index=True) ``` #### **步驟 3:寫入 CSV** 禁用索引和標題行,直接寫入數據: ```python df_res.to_csv(output_file, index=False, header=False) ``` --- ### **3. 完整代碼** ```python import pandas as pd # 讀取數據 df_head = pd.read_csv(wind_file, nrows=1) df_data = pd.read_csv(wind_file, skiprows=1) # 處理時間列並過濾數據 df_data['Time and Date'] = pd.to_datetime(df_data['Time and Date']) df_filterd = df_data[(df_data['Time and Date'] >= st) & (df_data['Time and Date'] <= et)] # 統一列名並合併 df_filterd.columns = df_head.columns.tolist() df_res = pd.concat([df_head, df_filterd], ignore_index=True) # 寫入 CSV(不包含索引和標題) df_res.to_csv(output_file, index=False, header=False) ``` --- ### **4. 驗證邏輯** 1. **列名一致性**:通過 `df_filterd.columns = df_head.columns` 確保兩者的列名完全匹配。 2. **索引重置**:`ignore_index=True` 避免合併後索引不連續。 3. **寫入控制**:`index=False` 和 `header=False` 確保只寫入純數據,第一行為 `df_head`,後續為 `df_filterd`。 --- ### **5. 常見問題** - **若 CSV 原本有標題行**:需調整讀取方式,例如先讀取標題行,再讀取數據部分。 - **時間格式錯誤**:檢查 `pd.to_datetime` 是否正確解析時間列,必要時指定格式參數 `format`。 通過以上步驟,即可正確將 `df_head` 寫入首行,並將 `df_filterd` 從第二行開始寫入 CSV。
阅读全文

相关推荐

import numpy as np import pandas as pd import os # 检查文件是否存在 def check_file_exists(file_path): if not os.path.exists(file_path): raise FileNotFoundError(f"文件 {file_path} 不存在,请检查路径是否正确") # 1. 数据加载与预处理 # 加载季度GDP数据 quarterly_gdp_path = '季度GDP.xlsx' check_file_exists(quarterly_gdp_path) quarterly_gdp = pd.read_excel(quarterly_gdp_path, engine='openpyxl') # 处理季度GDP的日期格式 def convert_quarter_date(date_str): quarter, year = date_str.split('-') quarter_map = {'I': '03', 'II': '06', 'III': '09', 'IV': '12'} month = quarter_map.get(quarter, '03') return pd.to_datetime(f"{year}-{month}-01") quarterly_gdp['jidu'] = quarterly_gdp['jidu'].apply(convert_quarter_date) quarterly_gdp.set_index('jidu', inplace=True) quarterly_gdp.rename(columns={'gdp': 'GDP_Q'}, inplace=True) # 加载月度数据 monthly_data_path = '四大行业月度数据.xlsx' check_file_exists(monthly_data_path) monthly_data = pd.read_excel(monthly_data_path, engine='openpyxl') # 检查月度数据内容 if 'MONTH' not in monthly_data.columns: raise ValueError("月度数据文件中没有找到 'MONTH' 列") # 处理月度数据的日期格式 monthly_data['MONTH'] = pd.to_datetime(monthly_data['MONTH'], format='%Y-%m') monthly_data.set_index('MONTH', inplace=True) monthly_data.rename(columns={'INV': 'INV', 'TRADE': 'TRADE', 'POWER': 'POWER', 'IMEX': 'IMEX'}, inplace=True) 前面的代码是这样的 里面有数据信息 怎么改

优化代码 def cluster_format(self, start_time, end_time, save_on=True, data_clean=False, data_name=None): """ local format function is to format data from beihang. :param start_time: :param end_time: :return: """ # 户用簇级数据清洗 if data_clean: unused_index_col = [i for i in self.df.columns if 'Unnamed' in i] self.df.drop(columns=unused_index_col, inplace=True) self.df.drop_duplicates(inplace=True, ignore_index=True) self.df.reset_index(drop=True, inplace=True) dupli_header_lines = np.where(self.df['sendtime'] == 'sendtime')[0] self.df.drop(index=dupli_header_lines, inplace=True) self.df = self.df.apply(pd.to_numeric, errors='ignore') self.df['sendtime'] = pd.to_datetime(self.df['sendtime']) self.df.sort_values(by='sendtime', inplace=True, ignore_index=True) self.df.to_csv(data_name, index=False) # 调用基本格式化处理 self.df = super().format(start_time, end_time) module_number_register = np.unique(self.df['bat_module_num']) # if registered m_num is 0 and not changed, there is no module data if not np.any(module_number_register): logger.logger.warning("No module data!") sys.exit() if 'bat_module_voltage_00' in self.df.columns: volt_ref = 'bat_module_voltage_00' elif 'bat_module_voltage_01' in self.df.columns: volt_ref = 'bat_module_voltage_01' elif 'bat_module_voltage_02' in self.df.columns: volt_ref = 'bat_module_voltage_02' else: logger.logger.warning("No module data!") sys.exit() self.df.dropna(axis=0, subset=[volt_ref], inplace=True) self.df.reset_index(drop=True, inplace=True) self.headers = list(self.df.columns) # time duration of a cluster self.length = len(self.df) if self.length == 0: logger.logger.warning("After cluster data clean, no effective data!") raise ValueError("No effective data after cluster data clean.") self.cluster_stats(save_on) for m in range(self.mod_num): print(self.clusterid, self.mod_num) self.module_list.append(np.unique(self.df[f'bat_module_sn_{str(m).zfill(2)}'].dropna())[0])

import tkinter as tk from tkinter import ttk, filedialog, messagebox, scrolledtext import pandas as pd import numpy as np import os import re class ExcelProcessor: def __init__(self, root): self.root = root self.root.title("Excel数据处理器") self.root.geometry("900x600") self.df = None self.create_widgets() def create_widgets(self): # 顶部控制区域 control_frame = ttk.Frame(self.root, padding=10) control_frame.pack(fill=tk.X) # 文件选择按钮 ttk.Button(control_frame, text="选择Excel文件", command=self.load_excel).grid(row=0, column=0, padx=5) # 处理方式选择 self.process_var = tk.StringVar(value="点击选择") ttk.Label(control_frame, text="处理方式:").grid(row=0, column=1, padx=5) process_combo = ttk.Combobox(control_frame, textvariable=self.process_var, width=15) process_combo['values'] = ( '统计', '预处理','数据排序', '数据切分','保存结果') process_combo.grid(row=0, column=2, padx=5) # 执行按钮 ttk.Button(control_frame, text="执行", command=self.process_data).grid(row=0, column=3, padx=5) # 数据展示区域 self.notebook = ttk.Notebook(self.root) self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 预览标签页 self.preview_frame = ttk.Frame(self.notebook) self.notebook.add(self.preview_frame, text="数据展示") # 统计标签页 self.stats_frame = ttk.Frame(self.notebook) self.notebook.add(self.stats_frame, text="统计信息") # 状态栏 self.status_var = tk.StringVar(value="就绪") ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W).pack(fill=tk.X, side=tk.BOTTOM) def load_excel(self): """加载Excel文件""" file_path = filedialog.askopenfilename( title="选择Excel文件", filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")] ) if not file_path: return try: self.status_var.set(f"正在加载: {os.path.basename(file_path)}...") self.root.update() # 更新界面显示状态 # 读取Excel文件 self.df = pd.read_excel(file_path) # 显示预览数据 self.show_preview() self.status_var.set( f"已加载: {os.path.basename(file_path)} | 行数: {len(self.df)} | 列数: {len(self.df.columns)}") except Exception as e: messagebox.showerror("加载错误", f"无法读取Excel文件:\n{str(e)}") self.status_var.set("加载失败") def preprocess_data(self): """数据预处理对话框 - 整合全部预处理功能""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return preprocess_window = tk.Toplevel(self.root) preprocess_window.title("数据预处理") preprocess_window.geometry("650x800") main_frame = ttk.Frame(preprocess_window) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # ================ 新增:功能启用复选框 ================ enable_frame = ttk.LabelFrame(main_frame, text="启用功能", padding=10) enable_frame.pack(fill=tk.X, pady=5) # 创建启用变量 self.enable_missing = tk.BooleanVar(value=True) self.enable_outlier = tk.BooleanVar(value=True) self.enable_datetime = tk.BooleanVar(value=True) self.enable_lag = tk.BooleanVar(value=True) ttk.Checkbutton(enable_frame, text="执行缺失值处理", variable=self.enable_missing).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="执行异常值处理", variable=self.enable_outlier).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="执行时间列转换", variable=self.enable_datetime).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="添加滞后特征", variable=self.enable_lag).pack(anchor=tk.W) # ================================================= # 1. 缺失值处理部分 missing_frame = ttk.LabelFrame(main_frame, text="缺失值处理", padding=10) missing_frame.pack(fill=tk.X, pady=5) # 缺失值统计显示 missing_stats = self.df.isnull().sum() missing_text = scrolledtext.ScrolledText(missing_frame, height=4) missing_text.pack(fill=tk.X) for col, count in missing_stats.items(): if count > 0: missing_text.insert(tk.END, f"{col}: {count}个缺失值\n") missing_text.config(state=tk.DISABLED) # 缺失值处理方法选择 ttk.Label(missing_frame, text="处理方法:").pack(anchor=tk.W) missing_method_var = tk.StringVar(value="fill") missing_method_frame = ttk.Frame(missing_frame) missing_method_frame.pack(fill=tk.X, pady=5) ttk.Radiobutton(missing_method_frame, text="删除缺失行", variable=missing_method_var, value="drop").pack( side=tk.LEFT) ttk.Radiobutton(missing_method_frame, text="固定值填充", variable=missing_method_var, value="fill").pack( side=tk.LEFT) ttk.Radiobutton(missing_method_frame, text="插值法", variable=missing_method_var, value="interpolate").pack( side=tk.LEFT) # 填充选项 fill_options_frame = ttk.Frame(missing_frame) fill_options_frame.pack(fill=tk.X, pady=5) ttk.Label(fill_options_frame, text="填充值:").pack(side=tk.LEFT) fill_value_entry = ttk.Entry(fill_options_frame, width=10) fill_value_entry.pack(side=tk.LEFT, padx=5) fill_value_entry.insert(0, "0") ttk.Label(fill_options_frame, text="或选择:").pack(side=tk.LEFT, padx=5) fill_type_var = tk.StringVar(value="fixed") ttk.Radiobutton(fill_options_frame, text="前值填充", variable=fill_type_var, value="ffill").pack(side=tk.LEFT) ttk.Radiobutton(fill_options_frame, text="后值填充", variable=fill_type_var, value="bfill").pack(side=tk.LEFT) ttk.Radiobutton(fill_options_frame, text="均值填充", variable=fill_type_var, value="mean").pack(side=tk.LEFT) # 2. 异常值处理部分 outlier_frame = ttk.LabelFrame(main_frame, text="异常值处理", padding=10) outlier_frame.pack(fill=tk.X, pady=5) # 异常值检测方法 ttk.Label(outlier_frame, text="检测方法:").pack(anchor=tk.W) outlier_method_var = tk.StringVar(value="3sigma") outlier_method_frame = ttk.Frame(outlier_frame) outlier_method_frame.pack(fill=tk.X) ttk.Radiobutton(outlier_method_frame, text="3σ原则", variable=outlier_method_var, value="3sigma").pack( side=tk.LEFT) ttk.Radiobutton(outlier_method_frame, text="IQR方法", variable=outlier_method_var, value="iqr").pack( side=tk.LEFT) # 异常值处理方式 ttk.Label(outlier_frame, text="处理方式:").pack(anchor=tk.W) outlier_action_var = tk.StringVar(value="remove") outlier_action_frame = ttk.Frame(outlier_frame) outlier_action_frame.pack(fill=tk.X) ttk.Radiobutton(outlier_action_frame, text="删除", variable=outlier_action_var, value="remove").pack( side=tk.LEFT) ttk.Radiobutton(outlier_action_frame, text="用中位数替换", variable=outlier_action_var, value="median").pack( side=tk.LEFT) ttk.Radiobutton(outlier_action_frame, text="用前后均值替换", variable=outlier_action_var, value="neighbor").pack(side=tk.LEFT) # 3. 数据类型转换部分 type_frame = ttk.LabelFrame(main_frame, text="数据类型转换", padding=10) type_frame.pack(fill=tk.X, pady=5) # 时间列转换 ttk.Label(type_frame, text="时间列转换:").pack(anchor=tk.W) time_col_var = tk.StringVar() time_col_combo = ttk.Combobox(type_frame, textvariable=time_col_var, width=20) time_col_combo['values'] = tuple(self.df.columns) time_col_combo.pack(anchor=tk.W, pady=5) # === 新增:时间单位选择 === time_units_frame = ttk.Frame(type_frame) time_units_frame.pack(fill=tk.X, pady=5) ttk.Label(time_units_frame, text="提取时间单位:").pack(side=tk.LEFT) # 创建时间单位变量 self.extract_year = tk.BooleanVar(value=True) self.extract_month = tk.BooleanVar(value=True) self.extract_day = tk.BooleanVar(value=True) self.extract_hour = tk.BooleanVar(value=False) self.extract_minute = tk.BooleanVar(value=False) self.extract_second = tk.BooleanVar(value=False) # 添加复选框 ttk.Checkbutton(time_units_frame, text="年", variable=self.extract_year).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="月", variable=self.extract_month).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="日", variable=self.extract_day).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="时", variable=self.extract_hour).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="分", variable=self.extract_minute).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="秒", variable=self.extract_second).pack(side=tk.LEFT, padx=5) # === 修改时间转换逻辑 === if self.enable_datetime.get(): time_col = time_col_var.get() if time_col and time_col in self.df.columns: try: # 统一处理不同日期格式 self.df[time_col] = self.df[time_col].apply( lambda x: pd.to_datetime(x, errors='coerce', format='mixed') ) # 强制显示完整时间格式 pd.set_option('display.datetime_format', '%Y-%m-%d %H:%M:%S') # 根据用户选择提取时间单位 if self.extract_year.get(): self.df['year'] = self.df[time_col].dt.year if self.extract_month.get(): self.df['month'] = self.df[time_col].dt.month if self.extract_day.get(): self.df['day'] = self.df[time_col].dt.day if self.extract_hour.get(): self.df['hour'] = self.df[time_col].dt.hour if self.extract_minute.get(): self.df['minute'] = self.df[time_col].dt.minute if self.extract_second.get(): self.df['second'] = self.df[time_col].dt.second # 新增:确保时间部分显示 self.df['full_datetime'] = self.df[time_col].dt.strftime('%Y-%m-%d %H:%M:%S') # 时间周期特征 if self.extract_hour.get() or self.extract_minute.get(): self.df['time_of_day'] = self.df[time_col].dt.hour + self.df[time_col].dt.minute / 60.0 if self.extract_second.get(): self.df['time_of_day'] += self.df[time_col].dt.second / 3600.0 except Exception as e: messagebox.showerror("时间转换错误", f"时间列转换失败: {str(e)}") # 4. 特征工程部分 feature_frame = ttk.LabelFrame(main_frame, text="特征工程", padding=10) feature_frame.pack(fill=tk.X, pady=5) # 添加滞后特征 ttk.Label(feature_frame, text="滞后特征:").pack(anchor=tk.W) lag_frame = ttk.Frame(feature_frame) lag_frame.pack(fill=tk.X) ttk.Label(lag_frame, text="选择列:").pack(side=tk.LEFT) lag_col_var = tk.StringVar() lag_col_combo = ttk.Combobox(lag_frame, textvariable=lag_col_var, width=15) lag_col_combo['values'] = tuple(self.df.select_dtypes(include=['number']).columns) lag_col_combo.pack(side=tk.LEFT, padx=5) ttk.Label(lag_frame, text="滞后步数:").pack(side=tk.LEFT) lag_steps_entry = ttk.Entry(lag_frame, width=5) lag_steps_entry.pack(side=tk.LEFT) lag_steps_entry.insert(0, "1") # 执行预处理按钮 def apply_preprocessing(): try: original_shape = self.df.shape # 1. 处理缺失值 (如果启用) if self.enable_missing.get(): missing_method = missing_method_var.get() if missing_method == "drop": self.df = self.df.dropna() elif missing_method == "fill": fill_type = fill_type_var.get() if fill_type == "fixed": fill_value = fill_value_entry.get() self.df = self.df.fillna( float(fill_value) if self.df.select_dtypes(include=['number']).shape[ 1] > 0 else fill_value) elif fill_type == "ffill": self.df = self.df.ffill() elif fill_type == "bfill": self.df = self.df.bfill() elif fill_type == "mean": self.df = self.df.fillna(self.df.mean()) elif missing_method == "interpolate": self.df = self.df.interpolate() # 2. 处理异常值 (如果启用) if self.enable_outlier.get(): outlier_method = outlier_method_var.get() outlier_action = outlier_action_var.get() numeric_cols = self.df.select_dtypes(include=['number']).columns for col in numeric_cols: if outlier_method == "3sigma": mean, std = self.df[col].mean(), self.df[col].std() lower, upper = mean - 3 * std, mean + 3 * std else: # iqr q1, q3 = self.df[col].quantile(0.25), self.df[col].quantile(0.75) iqr = q3 - q1 lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr if outlier_action == "remove": self.df = self.df[(self.df[col] >= lower) & (self.df[col] <= upper)] elif outlier_action == "median": self.df.loc[(self.df[col] < lower) | (self.df[col] > upper), col] = self.df[col].median() elif outlier_action == "neighbor": mask = (self.df[col] < lower) | (self.df[col] > upper) self.df.loc[mask, col] = self.df[col].rolling(2, min_periods=1).mean()[mask] # 3. 时间列转换 (如果启用) if self.enable_datetime.get(): time_col = time_col_var.get() if time_col and time_col in self.df.columns: try: self.df[time_col] = pd.to_datetime(self.df[time_col]) self.df['year'] = self.df[time_col].dt.year self.df['month'] = self.df[time_col].dt.month self.df['day'] = self.df[time_col].dt.day except Exception as e: messagebox.showwarning("时间转换警告", f"时间列转换失败: {str(e)}") # 4. 添加滞后特征 (如果启用) if self.enable_lag.get(): lag_col = lag_col_var.get() if lag_col and lag_col in self.df.columns: try: lag_steps = int(lag_steps_entry.get()) self.df[f'{lag_col}_lag{lag_steps}'] = self.df[lag_col].shift(lag_steps) except Exception as e: messagebox.showwarning("滞后特征警告", f"创建滞后特征失败: {str(e)}") # ========================================================= # 更新显示 self.show_preview() preprocess_window.destroy() new_shape = self.df.shape self.status_var.set(f"预处理完成 | 原形状: {original_shape} | 新形状: {new_shape}") except Exception as e: messagebox.showerror("预处理错误", f"预处理过程中发生错误:\n{str(e)}") ttk.Button(main_frame, text="执行预处理", command=apply_preprocessing).pack(pady=10) def show_preview(self): """在表格中分页显示数据预览""" # 清除旧内容 for widget in self.preview_frame.winfo_children(): widget.destroy() # 创建主容器 container = ttk.Frame(self.preview_frame) container.pack(fill=tk.BOTH, expand=True) # 创建表格 columns = list(self.df.columns) self.tree = ttk.Treeview(container, columns=columns, show="headings") # 添加列标题 for col in columns: self.tree.heading(col, text=col) self.tree.column(col, width=100, anchor=tk.W) # 添加滚动条 scrollbar = ttk.Scrollbar(container, orient=tk.VERTICAL, command=self.tree.yview) self.tree.configure(yscroll=scrollbar.set) # 布局表格和滚动条 self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 创建分页控制面板 pagination_frame = ttk.Frame(self.preview_frame) pagination_frame.pack(fill=tk.X, pady=5) # 分页参数 self.current_page = 1 self.rows_per_page = 1000 # 每页显示的行数 self.total_pages = max(1, (len(self.df) + self.rows_per_page - 1) // self.rows_per_page) # 分页标签 self.page_label = ttk.Label(pagination_frame, text=f"第 {self.current_page} 页 / 共 {self.total_pages} 页") self.page_label.pack(side=tk.LEFT, padx=10) # 分页按钮 ttk.Button(pagination_frame, text="首页", command=lambda: self.change_page(1)).pack(side=tk.LEFT) ttk.Button(pagination_frame, text="上一页", command=lambda: self.change_page(self.current_page - 1)).pack( side=tk.LEFT) ttk.Button(pagination_frame, text="下一页", command=lambda: self.change_page(self.current_page + 1)).pack( side=tk.LEFT) ttk.Button(pagination_frame, text="末页", command=lambda: self.change_page(self.total_pages)).pack(side=tk.LEFT) # 跳转输入框 ttk.Label(pagination_frame, text="跳转到:").pack(side=tk.LEFT, padx=(10, 0)) self.page_entry = ttk.Entry(pagination_frame, width=5) self.page_entry.pack(side=tk.LEFT) ttk.Button(pagination_frame, text="跳转", command=self.jump_to_page).pack(side=tk.LEFT, padx=(5, 10)) # 显示第一页数据 self.load_page_data() def load_page_data(self): """加载当前页的数据""" # 清空现有数据 for item in self.tree.get_children(): self.tree.delete(item) # 计算起始和结束索引 start_idx = (self.current_page - 1) * self.rows_per_page end_idx = start_idx + self.rows_per_page # 添加当前页的数据行 for i, row in self.df.iloc[start_idx:end_idx].iterrows(): self.tree.insert("", tk.END, values=list(row)) # 更新分页标签 self.page_label.config(text=f"第 {self.current_page} 页 / 共 {self.total_pages} 页") self.page_entry.delete(0, tk.END) self.page_entry.insert(0, str(self.current_page)) def change_page(self, new_page): """切换页面""" # 确保新页码在有效范围内 new_page = max(1, min(new_page, self.total_pages)) if new_page != self.current_page: self.current_page = new_page self.load_page_data() def jump_to_page(self): """跳转到指定页码""" try: page_num = int(self.page_entry.get()) self.change_page(page_num) except ValueError: messagebox.showerror("错误", "请输入有效的页码数字") def process_data(self): """根据选择的处理方式处理数据""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return process_type = self.process_var.get() if process_type == "统计": self.show_statistics() self.notebook.select(1) elif process_type == "数据排序": self.sort_data() elif process_type == "保存结果": self.save_data() elif process_type == "预处理": self.preprocess_data() elif process_type == "数据切分": self.divide_data() def show_statistics(self): """显示数据统计信息""" # 清除旧内容 for widget in self.stats_frame.winfo_children(): widget.destroy() # 计算统计信息 stats = self.df.describe(include='all').fillna('-') # 创建表格显示统计信息 columns = ['统计项'] + list(stats.columns) tree = ttk.Treeview(self.stats_frame, columns=columns, show="headings") # 添加列标题 for col in columns: tree.heading(col, text=col) tree.column(col, width=100, anchor=tk.W) # 添加数据行 for index, row in stats.iterrows(): tree.insert("", tk.END, values=[index] + list(row)) # 添加滚动条 scrollbar = ttk.Scrollbar(self.stats_frame, orient=tk.VERTICAL, command=tree.yview) tree.configure(yscroll=scrollbar.set) # 布局 tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 添加数据类型信息 type_frame = ttk.LabelFrame(self.stats_frame, text="数据类型") type_frame.pack(fill=tk.X, padx=5, pady=5) type_text = scrolledtext.ScrolledText(type_frame, height=5) type_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) dtypes = self.df.dtypes.apply(lambda x: x.name).to_dict() type_info = "\n".join([f"{col}: {dtype}" for col, dtype in dtypes.items()]) type_text.insert(tk.END, type_info) type_text.config(state=tk.DISABLED) def sort_data(self): """数据排序对话框""" sort_window = tk.Toplevel(self.root) sort_window.title("数据排序") sort_window.geometry("400x300") ttk.Label(sort_window, text="选择排序列:").pack(pady=10) # 列选择 col_var = tk.StringVar() col_combo = ttk.Combobox(sort_window, textvariable=col_var, width=20) col_combo['values'] = tuple(self.df.columns) col_combo.pack(pady=5) # 排序方式 ttk.Label(sort_window, text="排序方式:").pack(pady=10) order_var = tk.StringVar(value="ascending") ttk.Radiobutton(sort_window, text="升序", variable=order_var, value="ascending").pack() ttk.Radiobutton(sort_window, text="降序", variable=order_var, value="descending").pack() def apply_sort(): if not col_var.get(): messagebox.showwarning("警告", "请选择排序列") return try: ascending = (order_var.get() == "ascending") self.df = self.df.sort_values(by=col_var.get(), ascending=ascending) self.show_preview() sort_window.destroy() self.status_var.set(f"数据已按 {col_var.get()} {'升序' if ascending else '降序'} 排序") except Exception as e: messagebox.showerror("排序错误", f"排序失败:\n{str(e)}") ttk.Button(sort_window, text="应用排序", command=apply_sort).pack(pady=20) def save_data(self): """保存处理结果""" if self.df is None or self.df.empty: messagebox.showwarning("警告", "没有可保存的数据") return save_path = filedialog.asksaveasfilename( defaultextension=".xlsx", filetypes=[("Excel文件", "*.xlsx"), ("CSV文件", "*.csv")] ) if not save_path: return try: if save_path.endswith('.xlsx'): self.df.to_excel(save_path, index=False) else: self.df.to_csv(save_path, index=False) self.status_var.set(f"文件已保存至: {os.path.basename(save_path)}") messagebox.showinfo("保存成功", f"文件已成功保存至:\n{save_path}") except Exception as e: messagebox.showerror("保存错误", f"保存文件失败:\n{str(e)}") # 创建并运行程序 if __name__ == "__main__": root = tk.Tk() app = ExcelProcessor(root) root.mainloop() 请你用相同的风格也一个excel处理器类的一个方法:可以对数据进行筛选

import numpy as np import pandas as pd import os from statsmodels.tsa.statespace.dynamic_factor_mq import DynamicFactorMQ import matplotlib.pyplot as plt # -------------------------- # 数据加载与预处理(修改部分) # -------------------------- def load_data(): # 加载季度GDP数据(保持原有处理) quarterly_gdp_path = '季度GDP.xlsx' check_file_exists(quarterly_gdp_path) quarterly_gdp = pd.read_excel(quarterly_gdp_path, engine='openpyxl') # 转换季度日期(关键改进:保留季度末日期) def convert_quarter_date(date_str): quarter, year = date_str.split('-') quarter_map = {'I': '03-31', 'II': '06-30', 'III': '09-30', 'IV': '12-31'} return pd.to_datetime(f"{year}-{quarter_map[quarter]}") quarterly_gdp['jidu'] = quarterly_gdp['jidu'].apply(convert_quarter_date) quarterly_gdp.set_index('jidu', inplace=True) quarterly_gdp.rename(columns={'gdp': 'GDP_Q'}, inplace=True) # 加载月度数据(保持原有处理) monthly_data_path = '四大行业月度数据.xlsx' check_file_exists(monthly_data_path) monthly_data = pd.read_excel(monthly_data_path, engine='openpyxl') if 'MONTH' not in monthly_data.columns: raise ValueError("月度数据文件中没有找到 'MONTH' 列") monthly_data['MONTH'] = pd.to_datetime(monthly_data['MONTH'], format='%Y-%m') monthly_data.set_index('MONTH', inplace=True) # 关键改进:统一列名规范 monthly_data.columns = ['INV', 'TRADE', 'POWER', 'IMEX'] # 假设原始列名正确对应 # 合并数据集(高频在前,低频在后)。 继续编写代码。构建月度gdp

start_time = time.time() othercon = 'Profile_Time >= "{}" and Profile_Time <"{}" and high_level > 338'.format(desday,tom_dt.strftime('%Y-%m-%d')) # apro_df 是[latitude,longitude,time,high_level,features]的格式,但是高度还没有std apro_ori, apro_df, apro_xr = get_apro_data_sql(con, apro_config, othercon, pos_merge=pos_df, multi_index=multi_index + ['high_level']) print('THE COST to get raw data table:',time.strftime("%H: %M: %S",time.gmtime(time.time() - start_time))) # TODO: 可能查不到数据,判断一下 if apro_df.shape[0] == 0: # 修改列名即可 apro_final_df = apro_df apro_final_df.rename(columns={'high_level':'Level'},inplace=True) print('THE {} DAY HAS NO APRO DATA'.format(desday)) else: # 高度标准化 apro_df['Level'] = apro_df.apply(apro_get_level, axis=1) apro_df = apro_df.drop(['high_level'], axis=1) apro_xr = apro_df.set_index(['Time', 'Latitude', 'Longitude', 'Level']).to_xarray() # 插值等 # 2. 插值 _, _, times, tlabels = get_apro_interp_attr(apro_xr, std_index_3d, desday,posrange) # 时间 apro_mean_xr = apro_xr.groupby_bins('Time', bins=times, labels=tlabels).mean('Time').rename( {'Time_bins': 'Time'}) # 位置 apro_mean_xr['Latitude'] = apro_mean_xr.Latitude.values.round(1) apro_mean_xr['Longitude'] = apro_mean_xr.Longitude.values.round(1) apro_mean_df = apro_mean_xr.to_dataframe().dropna(how='all').reset_index() # 最后 apro_final_df = apro_mean_df.groupby(['Time', 'Latitude', 'Longitude', 'Level']).mean().dropna(how='all') # apro_final_xr = apro_final_df.to_xarray() apro_final_df = apro_final_df.reset_index() # 修改时间 apro_final_df.Time = pd.to_datetime(apro_final_df['Time']) apro_final_df.Time = apro_final_df['Time'].apply(lambda x:x.replace(year=2023)) # Todo: 可以改成输入的年份 # 输出中间文件,可能是空文件 desday = desday.replace('2017','2023') outfile = os.path.join(apro_config.outpath,"apro_mid_{}.csv".format(desday)) apro_final_df.to_csv(outfile,index=False)

import pandas as pd import matplotlib.pyplot as plt import numpy as np from scipy import stats plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体显示中文 plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时负号 '-' 显示为方块的问题 def data_preprocessing(df): df['监测时间'] = pd.to_datetime(df['监测时间'], format='%Y-%m-%d %H') df = df.set_index('监测时间') full_range = pd.date_range(start=df.index.min(), end=df.index.max(), freq='h') df_clean = df.reindex(full_range) valid_ranges = { 'PH 值': (6.0, 9.0), '氨氮排放量': (0.01, 1.5), '化学需氧量排放量': (0.05, 5.0) } for col, (min_val, max_val) in valid_ranges.items(): mask = df_clean[col].between(min_val, max_val) df_clean[col] = df_clean[col].where(mask).interpolate(method='spline', order=3) return df_clean def timing_drawing(df): plt.figure(figsize=(15, 9)) plt.subplot(3, 1, 1) plt.plot(df['PH 值'], color='#1f77b4') plt.title('PH 值时序变化趋势', fontproperties='SimHei') plt.ylabel('PH 值', fontproperties='SimHei') plt.subplot(3, 1, 2) plt.plot(df['氨氮排放量'], color='#2ca02c') plt.title('氨氮排放量时序变化趋势', fontproperties='SimHei') plt.ylabel('mg/L', fontproperties='SimHei') plt.subplot(3, 1, 3) plt.plot(df['化学需氧量排放量'], color='#d62728') plt.title('化学需氧量排放量时序变化趋势', fontproperties='SimHei') plt.ylabel('mg/L', fontproperties='SimHei') plt.tight_layout() plt.savefig('时间序列图.png', dpi=300) plt.show() def statistical_analysis(df): stats_summary = df.describe().transpose() median_values = df.median() stats_summary['median'] = median_values.values stats_summary = stats_summary[['mean', 'median', 'std', 'max', 'min']] # 确保输出的表格有正确的列名和指标名字 stats_summary.index.name = '指标' stats_summary.reset_index(inplace=True) stats_summary.columns = ['指标', '均值', '中位数', '标准差', '最大值', '最小值'] print("统计量分析表:") print(stats_summary.to_markdown(index=False)) if __name__ == "__main__": raw_df = pd.read_excel('B 题附件.xls') processed_df = data_preprocessing(raw_df) processed_df.reset_index().to_excel('预处理数据.xlsx', index=True) timing_drawing(processed_df) statistical_analysis(processed_df) 上述代码只需要PH值、氨氮排放量、化学需氧量排放量

import tkinter as tk from tkinter import ttk, filedialog, messagebox, scrolledtext import pandas as pd import numpy as np import os import re class ExcelProcessor: def init(self, root): self.root = root self.root.title(“Excel数据预处理和切分”) self.root.geometry(“1000x600”) self.df = None self.create_widgets() def create_widgets(self): # 顶部控制区域 control_frame = ttk.Frame(self.root, padding=10) control_frame.pack(fill=tk.X) # 文件选择按钮 ttk.Button(control_frame, text="选择Excel文件", command=self.load_excel).grid(row=0, column=0, padx=5) # 处理方式选择 self.process_var = tk.StringVar(value="点击选择") ttk.Label(control_frame, text="处理方式:").grid(row=0, column=1, padx=5) process_combo = ttk.Combobox(control_frame, textvariable=self.process_var, width=15) process_combo['values'] = ( '预处理','数据排序','数据筛选','数据切分','保存结果') process_combo.grid(row=0, column=2, padx=5) # 执行按钮 ttk.Button(control_frame, text="执行", command=self.process_data).grid(row=0, column=3, padx=5) # 数据展示区域 self.notebook = ttk.Notebook(self.root) self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 预览标签页 self.preview_frame = ttk.Frame(self.notebook) self.notebook.add(self.preview_frame, text="数据展示") # 状态栏 self.status_var = tk.StringVar(value="就绪") ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W).pack(fill=tk.X, side=tk.BOTTOM) def load_excel(self): """加载Excel文件""" file_path = filedialog.askopenfilename( title="选择Excel文件", filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")] ) if not file_path: return try: self.status_var.set(f"正在加载: {os.path.basename(file_path)}...") self.root.update() # 更新界面显示状态 # 读取Excel文件 self.df = pd.read_excel(file_path) # 显示预览数据 self.show_preview() self.status_var.set( f"已加载: {os.path.basename(file_path)} | 行数: {len(self.df)} | 列数: {len(self.df.columns)}") except Exception as e: messagebox.showerror("加载错误", f"无法读取Excel文件:\n{str(e)}") self.status_var.set("加载失败") def preprocess_data(self): """数据预处理对话框 - 整合全部预处理功能""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return preprocess_window = tk.Toplevel(self.root) preprocess_window.title("数据预处理") preprocess_window.geometry("650x800") main_frame = ttk.Frame(preprocess_window) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # ================ 新增:功能启用复选框 ================ enable_frame = ttk.LabelFrame(main_frame, text="启用功能", padding=10) enable_frame.pack(fill=tk.X, pady=5) # 创建启用变量 self.enable_missing = tk.BooleanVar(value=True) self.enable_outlier = tk.BooleanVar(value=True) self.enable_datetime = tk.BooleanVar(value=True) self.enable_lag = tk.BooleanVar(value=True) ttk.Checkbutton(enable_frame, text="执行缺失值处理", variable=self.enable_missing).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="执行异常值处理", variable=self.enable_outlier).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="执行时间列转换", variable=self.enable_datetime).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="添加滞后特征", variable=self.enable_lag).pack(anchor=tk.W) # ================================================= # 1. 缺失值处理部分 missing_frame = ttk.LabelFrame(main_frame, text="缺失值处理", padding=10) missing_frame.pack(fill=tk.X, pady=5) # 缺失值统计显示 missing_stats = self.df.isnull().sum() missing_text = scrolledtext.ScrolledText(missing_frame, height=4) missing_text.pack(fill=tk.X) for col, count in missing_stats.items(): if count > 0: missing_text.insert(tk.END, f"{col}: {count}个缺失值\n") missing_text.config(state=tk.DISABLED) # 缺失值处理方法选择 ttk.Label(missing_frame, text="处理方法:").pack(anchor=tk.W) missing_method_var = tk.StringVar(value="fill") missing_method_frame = ttk.Frame(missing_frame) missing_method_frame.pack(fill=tk.X, pady=5) ttk.Radiobutton(missing_method_frame, text="删除缺失行", variable=missing_method_var, value="drop").pack( side=tk.LEFT) ttk.Radiobutton(missing_method_frame, text="固定值填充", variable=missing_method_var, value="fill").pack( side=tk.LEFT) ttk.Radiobutton(missing_method_frame, text="插值法", variable=missing_method_var, value="interpolate").pack( side=tk.LEFT) # 填充选项 fill_options_frame = ttk.Frame(missing_frame) fill_options_frame.pack(fill=tk.X, pady=5) ttk.Label(fill_options_frame, text="填充值:").pack(side=tk.LEFT) fill_value_entry = ttk.Entry(fill_options_frame, width=10) fill_value_entry.pack(side=tk.LEFT, padx=5) fill_value_entry.insert(0, "0") ttk.Label(fill_options_frame, text="或选择:").pack(side=tk.LEFT, padx=5) fill_type_var = tk.StringVar(value="fixed") ttk.Radiobutton(fill_options_frame, text="前值填充", variable=fill_type_var, value="ffill").pack(side=tk.LEFT) ttk.Radiobutton(fill_options_frame, text="后值填充", variable=fill_type_var, value="bfill").pack(side=tk.LEFT) ttk.Radiobutton(fill_options_frame, text="均值填充", variable=fill_type_var, value="mean").pack(side=tk.LEFT) # 2. 异常值处理部分 outlier_frame = ttk.LabelFrame(main_frame, text="异常值处理", padding=10) outlier_frame.pack(fill=tk.X, pady=5) # 异常值检测方法 ttk.Label(outlier_frame, text="检测方法:").pack(anchor=tk.W) outlier_method_var = tk.StringVar(value="3sigma") outlier_method_frame = ttk.Frame(outlier_frame) outlier_method_frame.pack(fill=tk.X) ttk.Radiobutton(outlier_method_frame, text="3σ原则", variable=outlier_method_var, value="3sigma").pack( side=tk.LEFT) ttk.Radiobutton(outlier_method_frame, text="IQR方法", variable=outlier_method_var, value="iqr").pack( side=tk.LEFT) # 异常值处理方式 ttk.Label(outlier_frame, text="处理方式:").pack(anchor=tk.W) outlier_action_var = tk.StringVar(value="remove") outlier_action_frame = ttk.Frame(outlier_frame) outlier_action_frame.pack(fill=tk.X) ttk.Radiobutton(outlier_action_frame, text="删除", variable=outlier_action_var, value="remove").pack( side=tk.LEFT) ttk.Radiobutton(outlier_action_frame, text="用中位数替换", variable=outlier_action_var, value="median").pack( side=tk.LEFT) ttk.Radiobutton(outlier_action_frame, text="用前后均值替换", variable=outlier_action_var, value="neighbor").pack(side=tk.LEFT) # 3. 数据类型转换部分 type_frame = ttk.LabelFrame(main_frame, text="数据类型转换", padding=10) type_frame.pack(fill=tk.X, pady=5) # 时间列转换 ttk.Label(type_frame, text="时间列转换:").pack(anchor=tk.W) time_col_var = tk.StringVar() time_col_combo = ttk.Combobox(type_frame, textvariable=time_col_var, width=20) time_col_combo['values'] = tuple(self.df.columns) time_col_combo.pack(anchor=tk.W, pady=5) # === 新增:时间单位选择 === time_units_frame = ttk.Frame(type_frame) time_units_frame.pack(fill=tk.X, pady=5) ttk.Label(time_units_frame, text="提取时间单位:").pack(side=tk.LEFT) # 创建时间单位变量 self.extract_year = tk.BooleanVar(value=True) self.extract_month = tk.BooleanVar(value=True) self.extract_day = tk.BooleanVar(value=True) self.extract_hour = tk.BooleanVar(value=False) self.extract_minute = tk.BooleanVar(value=False) self.extract_second = tk.BooleanVar(value=False) # 添加复选框 ttk.Checkbutton(time_units_frame, text="年", variable=self.extract_year).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="月", variable=self.extract_month).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="日", variable=self.extract_day).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="时", variable=self.extract_hour).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="分", variable=self.extract_minute).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="秒", variable=self.extract_second).pack(side=tk.LEFT, padx=5) # === 修改时间转换逻辑 === if self.enable_datetime.get(): time_col = time_col_var.get() if time_col and time_col in self.df.columns: try: # 统一处理不同日期格式 self.df[time_col] = self.df[time_col].apply( lambda x: pd.to_datetime(x, errors='coerce', format='mixed') ) # 强制显示完整时间格式 pd.set_option('display.datetime_format', '%Y-%m-%d %H:%M:%S') # 根据用户选择提取时间单位 if self.extract_year.get(): self.df['year'] = self.df[time_col].dt.year if self.extract_month.get(): self.df['month'] = self.df[time_col].dt.month if self.extract_day.get(): self.df['day'] = self.df[time_col].dt.day if self.extract_hour.get(): self.df['hour'] = self.df[time_col].dt.hour if self.extract_minute.get(): self.df['minute'] = self.df[time_col].dt.minute if self.extract_second.get(): self.df['second'] = self.df[time_col].dt.second # 新增:确保时间部分显示 self.df['full_datetime'] = self.df[time_col].dt.strftime('%Y-%m-%d %H:%M:%S') # 时间周期特征 if self.extract_hour.get() or self.extract_minute.get(): self.df['time_of_day'] = self.df[time_col].dt.hour + self.df[time_col].dt.minute / 60.0 if self.extract_second.get(): self.df['time_of_day'] += self.df[time_col].dt.second / 3600.0 except Exception as e: messagebox.showerror("时间转换错误", f"时间列转换失败: {str(e)}") # 4. 特征工程部分 feature_frame = ttk.LabelFrame(main_frame, text="特征工程", padding=10) feature_frame.pack(fill=tk.X, pady=5) # 添加滞后特征 ttk.Label(feature_frame, text="滞后特征:").pack(anchor=tk.W) lag_frame = ttk.Frame(feature_frame) lag_frame.pack(fill=tk.X) ttk.Label(lag_frame, text="选择列:").pack(side=tk.LEFT) lag_col_var = tk.StringVar() lag_col_combo = ttk.Combobox(lag_frame, textvariable=lag_col_var, width=15) lag_col_combo['values'] = tuple(self.df.select_dtypes(include=['number']).columns) lag_col_combo.pack(side=tk.LEFT, padx=5) ttk.Label(lag_frame, text="滞后步数:").pack(side=tk.LEFT) lag_steps_entry = ttk.Entry(lag_frame, width=5) lag_steps_entry.pack(side=tk.LEFT) lag_steps_entry.insert(0, "1") # 执行预处理按钮 def apply_preprocessing(): try: original_shape = self.df.shape # 1. 处理缺失值 (如果启用) if self.enable_missing.get(): missing_method = missing_method_var.get() if missing_method == "drop": self.df = self.df.dropna() elif missing_method == "fill": fill_type = fill_type_var.get() if fill_type == "fixed": fill_value = fill_value_entry.get() self.df = self.df.fillna( float(fill_value) if self.df.select_dtypes(include=['number']).shape[ 1] > 0 else fill_value) elif fill_type == "ffill": self.df = self.df.ffill() elif fill_type == "bfill": self.df = self.df.bfill() elif fill_type == "mean": self.df = self.df.fillna(self.df.mean()) elif missing_method == "interpolate": self.df = self.df.interpolate() # 2. 处理异常值 (如果启用) if self.enable_outlier.get(): outlier_method = outlier_method_var.get() outlier_action = outlier_action_var.get() numeric_cols = self.df.select_dtypes(include=['number']).columns for col in numeric_cols: if outlier_method == "3sigma": mean, std = self.df[col].mean(), self.df[col].std() lower, upper = mean - 3 * std, mean + 3 * std else: # iqr q1, q3 = self.df[col].quantile(0.25), self.df[col].quantile(0.75) iqr = q3 - q1 lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr if outlier_action == "remove": self.df = self.df[(self.df[col] >= lower) & (self.df[col] <= upper)] elif outlier_action == "median": self.df.loc[(self.df[col] < lower) | (self.df[col] > upper), col] = self.df[col].median() elif outlier_action == "neighbor": mask = (self.df[col] < lower) | (self.df[col] > upper) self.df.loc[mask, col] = self.df[col].rolling(2, min_periods=1).mean()[mask] # 3. 时间列转换 (如果启用) if self.enable_datetime.get(): time_col = time_col_var.get() if time_col and time_col in self.df.columns: try: self.df[time_col] = pd.to_datetime(self.df[time_col]) self.df['year'] = self.df[time_col].dt.year self.df['month'] = self.df[time_col].dt.month self.df['day'] = self.df[time_col].dt.day except Exception as e: messagebox.showwarning("时间转换警告", f"时间列转换失败: {str(e)}") # 4. 添加滞后特征 (如果启用) if self.enable_lag.get(): lag_col = lag_col_var.get() if lag_col and lag_col in self.df.columns: try: lag_steps = int(lag_steps_entry.get()) self.df[f'{lag_col}_lag{lag_steps}'] = self.df[lag_col].shift(lag_steps) except Exception as e: messagebox.showwarning("滞后特征警告", f"创建滞后特征失败: {str(e)}") # ========================================================= # 更新显示 self.show_preview() preprocess_window.destroy() new_shape = self.df.shape self.status_var.set(f"预处理完成 | 原形状: {original_shape} | 新形状: {new_shape}") except Exception as e: messagebox.showerror("预处理错误", f"预处理过程中发生错误:\n{str(e)}") ttk.Button(main_frame, text="执行预处理", command=apply_preprocessing).pack(pady=10) def show_preview(self): """在表格中分页显示数据预览""" # 清除旧内容 for widget in self.preview_frame.winfo_children(): widget.destroy() # 创建主容器 container = ttk.Frame(self.preview_frame) container.pack(fill=tk.BOTH, expand=True) # 创建表格 columns = list(self.df.columns) self.tree = ttk.Treeview(container, columns=columns, show="headings") # 添加列标题 for col in columns: self.tree.heading(col, text=col) self.tree.column(col, width=100, anchor=tk.W) # 添加滚动条 scrollbar = ttk.Scrollbar(container, orient=tk.VERTICAL, command=self.tree.yview) self.tree.configure(yscroll=scrollbar.set) # 布局表格和滚动条 self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 创建分页控制面板 pagination_frame = ttk.Frame(self.preview_frame) pagination_frame.pack(fill=tk.X, pady=5) # 分页参数 self.current_page = 1 self.rows_per_page = 1000 # 每页显示的行数 self.total_pages = max(1, (len(self.df) + self.rows_per_page - 1) // self.rows_per_page) # 分页标签 self.page_label = ttk.Label(pagination_frame, text=f"第 {self.current_page} 页 / 共 {self.total_pages} 页") self.page_label.pack(side=tk.LEFT, padx=10) # 分页按钮 ttk.Button(pagination_frame, text="首页", command=lambda: self.change_page(1)).pack(side=tk.LEFT) ttk.Button(pagination_frame, text="上一页", command=lambda: self.change_page(self.current_page - 1)).pack( side=tk.LEFT) ttk.Button(pagination_frame, text="下一页", command=lambda: self.change_page(self.current_page + 1)).pack( side=tk.LEFT) ttk.Button(pagination_frame, text="末页", command=lambda: self.change_page(self.total_pages)).pack(side=tk.LEFT) # 跳转输入框 ttk.Label(pagination_frame, text="跳转到:").pack(side=tk.LEFT, padx=(10, 0)) self.page_entry = ttk.Entry(pagination_frame, width=5) self.page_entry.pack(side=tk.LEFT) ttk.Button(pagination_frame, text="跳转", command=self.jump_to_page).pack(side=tk.LEFT, padx=(5, 10)) # 显示第一页数据 self.load_page_data() def load_page_data(self): """加载当前页的数据""" # 清空现有数据 for item in self.tree.get_children(): self.tree.delete(item) # 计算起始和结束索引 start_idx = (self.current_page - 1) * self.rows_per_page end_idx = start_idx + self.rows_per_page # 添加当前页的数据行 for i, row in self.df.iloc[start_idx:end_idx].iterrows(): self.tree.insert("", tk.END, values=list(row)) # 更新分页标签 self.page_label.config(text=f"第 {self.current_page} 页 / 共 {self.total_pages} 页") self.page_entry.delete(0, tk.END) self.page_entry.insert(0, str(self.current_page)) def change_page(self, new_page): """切换页面""" # 确保新页码在有效范围内 new_page = max(1, min(new_page, self.total_pages)) if new_page != self.current_page: self.current_page = new_page self.load_page_data() def jump_to_page(self): """跳转到指定页码""" try: page_num = int(self.page_entry.get()) self.change_page(page_num) except ValueError: messagebox.showerror("错误", "请输入有效的页码数字") def process_data(self): """根据选择的处理方式处理数据""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return process_type = self.process_var.get() if process_type == "数据排序": self.sort_data() elif process_type == "保存结果": self.save_data() elif process_type == "预处理": self.preprocess_data() elif process_type == "数据切分": self.divide_data() elif process_type == "数据筛选": self.filter_data() def sort_data(self): """数据排序对话框""" sort_window = tk.Toplevel(self.root) sort_window.title("数据排序") sort_window.geometry("400x300") ttk.Label(sort_window, text="选择排序列:").pack(pady=10) # 列选择 col_var = tk.StringVar() col_combo = ttk.Combobox(sort_window, textvariable=col_var, width=20) col_combo['values'] = tuple(self.df.columns) col_combo.pack(pady=5) # 排序方式 ttk.Label(sort_window, text="排序方式:").pack(pady=10) order_var = tk.StringVar(value="ascending") ttk.Radiobutton(sort_window, text="升序", variable=order_var, value="ascending").pack() ttk.Radiobutton(sort_window, text="降序", variable=order_var, value="descending").pack() def apply_sort(): if not col_var.get(): messagebox.showwarning("警告", "请选择排序列") return try: ascending = (order_var.get() == "ascending") self.df = self.df.sort_values(by=col_var.get(), ascending=ascending) self.show_preview() sort_window.destroy() self.status_var.set(f"数据已按 {col_var.get()} {'升序' if ascending else '降序'} 排序") except Exception as e: messagebox.showerror("排序错误", f"排序失败:\n{str(e)}") ttk.Button(sort_window, text="应用排序", command=apply_sort).pack(pady=20) def filter_data(self): """数据筛选对话框 - 支持多条件筛选""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return filter_window = tk.Toplevel(self.root) filter_window.title("数据筛选") filter_window.geometry("700x600") main_frame = ttk.Frame(filter_window, padding=10) main_frame.pack(fill=tk.BOTH, expand=True) # 条件容器 conditions_frame = ttk.LabelFrame(main_frame, text="筛选条件", padding=10) conditions_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 条件列表 self.filter_conditions = [] # 添加初始条件行 def add_condition_row(parent_frame, index=0): """添加单行筛选条件""" condition_frame = ttk.Frame(parent_frame) condition_frame.pack(fill=tk.X, pady=5) # 列选择 col_var = tk.StringVar() col_combo = ttk.Combobox(condition_frame, textvariable=col_var, width=15) col_combo['values'] = tuple(self.df.columns) col_combo.pack(side=tk.LEFT, padx=5) # 运算符选择 operator_var = tk.StringVar(value="==") operator_combo = ttk.Combobox(condition_frame, textvariable=operator_var, width=5) operator_combo['values'] = ("==", "!=", ">", ">=", "<", "<=", "包含", "不包含", "开头是", "结尾是") operator_combo.pack(side=tk.LEFT, padx=5) # 值输入 value_var = tk.StringVar() value_entry = ttk.Entry(condition_frame, textvariable=value_var, width=20) value_entry.pack(side=tk.LEFT, padx=5) # 删除按钮 def remove_condition(): condition_frame.destroy() self.filter_conditions.remove((col_var, operator_var, value_var)) remove_btn = ttk.Button(condition_frame, text="×", width=2, command=remove_condition) remove_btn.pack(side=tk.RIGHT, padx=5) # 逻辑关系选择(从第二行开始) if index > 0: logic_var = tk.StringVar(value="AND") logic_combo = ttk.Combobox(condition_frame, textvariable=logic_var, width=5) logic_combo['values'] = ("AND", "OR") logic_combo.pack(side=tk.LEFT, padx=5) return (col_var, operator_var, value_var, logic_var) else: return (col_var, operator_var, value_var, None) # 添加条件按钮 def add_condition(): new_condition = add_condition_row(conditions_frame, len(self.filter_conditions)) self.filter_conditions.append(new_condition) # 初始添加两行条件 self.filter_conditions.append(add_condition_row(conditions_frame)) self.filter_conditions.append(add_condition_row(conditions_frame, 1)) add_btn = ttk.Button(main_frame, text="添加条件", command=add_condition) add_btn.pack(anchor=tk.W, pady=5) # 预览区域 preview_frame = ttk.LabelFrame(main_frame, text="筛选结果预览", padding=10) preview_frame.pack(fill=tk.BOTH, expand=True, pady=5) preview_tree = ttk.Treeview(preview_frame, show="headings") preview_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) vsb = ttk.Scrollbar(preview_frame, orient="vertical", command=preview_tree.yview) vsb.pack(side=tk.RIGHT, fill=tk.Y) preview_tree.configure(yscrollcommand=vsb.set) # 更新预览 def update_preview(): """更新筛选结果预览""" try: # 清空现有预览 for item in preview_tree.get_children(): preview_tree.delete(item) # 如果没有条件,显示所有数据 if not any(cond[0].get() for cond in self.filter_conditions): filtered_df = self.df.head(100) # 限制预览行数 else: # 构建查询字符串 query_parts = [] for i, (col_var, operator_var, value_var, logic_var) in enumerate(self.filter_conditions): if not col_var.get() or not value_var.get(): continue col = col_var.get() operator = operator_var.get() value = value_var.get() # 处理数值类型 if self.df[col].dtype in (int, float): try: value = float(value) except ValueError: messagebox.showwarning("类型错误", f"列 '{col}' 是数值类型,请输入数字") return # 构建条件表达式 if operator in ("==", "!=", ">", ">=", "<", "<="): expr = f"{col} {operator} {repr(value)}" elif operator == "包含": expr = f"{col}.str.contains({repr(value)}, na=False)" elif operator == "不包含": expr = f"~{col}.str.contains({repr(value)}, na=False)" elif operator == "开头是": expr = f"{col}.str.startswith({repr(value)}, na=False)" elif operator == "结尾是": expr = f"{col}.str.endswith({repr(value)}, na=False)" # 添加逻辑关系(从第二个条件开始) if i > 0 and logic_var and logic_var.get(): expr = f" {logic_var.get()} {expr}" query_parts.append(expr) # 执行查询 query_str = "".join(query_parts) if query_str: filtered_df = self.df.query(query_str, engine='python').head(100) # 限制预览行数 else: filtered_df = self.df.head(100) # 更新预览表格 preview_tree["columns"] = list(filtered_df.columns) for col in filtered_df.columns: preview_tree.heading(col, text=col) preview_tree.column(col, width=100, anchor=tk.W) # 添加数据行 for _, row in filtered_df.iterrows(): preview_tree.insert("", tk.END, values=list(row)) # 更新状态 self.status_var.set(f"预览: {len(filtered_df)} 行 (显示前100条)") except Exception as e: messagebox.showerror("筛选错误", f"筛选条件错误:\n{str(e)}") # 应用筛选按钮 def apply_filter(): """应用筛选条件到主数据集""" try: # 构建查询字符串 query_parts = [] for i, (col_var, operator_var, value_var, logic_var) in enumerate(self.filter_conditions): if not col_var.get() or not value_var.get(): continue col = col_var.get() operator = operator_var.get() value = value_var.get() # 处理数值类型 if self.df[col].dtype in (int, float): try: value = float(value) except ValueError: messagebox.showwarning("类型错误", f"列 '{col}' 是数值类型,请输入数字") return # 构建条件表达式 if operator in ("==", "!=", ">", ">=", "<", "<="): expr = f"{col} {operator} {repr(value)}" elif operator == "包含": expr = f"{col}.str.contains({repr(value)}, na=False)" elif operator == "不包含": expr = f"~{col}.str.contains({repr(value)}, na=False)" elif operator == "开头是": expr = f"{col}.str.startswith({repr(value)}, na=False)" elif operator == "结尾是": expr = f"{col}.str.endswith({repr(value)}, na=False)" # 添加逻辑关系(从第二个条件开始) if i > 0 and logic_var and logic_var.get(): expr = f" {logic_var.get()} {expr}" query_parts.append(expr) # 执行查询 query_str = "".join(query_parts) if query_str: original_count = len(self.df) self.df = self.df.query(query_str, engine='python') new_count = len(self.df) # 更新显示 self.show_preview() filter_window.destroy() self.status_var.set(f"筛选完成 | 原始行数: {original_count} | 筛选后: {new_count}") messagebox.showinfo("筛选完成", f"数据筛选完成,保留 {new_count} 行数据") else: messagebox.showwarning("警告", "未设置有效筛选条件") except Exception as e: messagebox.showerror("筛选错误", f"应用筛选条件失败:\n{str(e)}") # 按钮区域 btn_frame = ttk.Frame(main_frame) btn_frame.pack(fill=tk.X, pady=10) ttk.Button(btn_frame, text="预览", command=update_preview).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="应用筛选", command=apply_filter).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="取消", command=filter_window.destroy).pack(side=tk.RIGHT, padx=5) # 初始预览 update_preview() def divide_data(self): """数据切分对话框 - 专门用于大坝渗流问题模型训练和测试""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return # 检查时间列是否存在 datetime_cols = [col for col in self.df.columns if pd.api.types.is_datetime64_any_dtype(self.df[col])] if not datetime_cols: messagebox.showwarning("警告", "未找到时间列,请先进行时间转换") return divide_window = tk.Toplevel(self.root) divide_window.title("大坝渗流数据切分") divide_window.geometry("600x550") main_frame = ttk.Frame(divide_window, padding=15) main_frame.pack(fill=tk.BOTH, expand=True) # 1. 时间列选择 time_frame = ttk.LabelFrame(main_frame, text="时间列选择", padding=10) time_frame.pack(fill=tk.X, pady=5) ttk.Label(time_frame, text="选择时间列:").pack(anchor=tk.W, pady=3) self.time_col_var = tk.StringVar(value=datetime_cols[0]) time_combo = ttk.Combobox(time_frame, textvariable=self.time_col_var, width=25) time_combo['values'] = tuple(datetime_cols) time_combo.pack(anchor=tk.W, fill=tk.X, pady=3) # 显示时间范围 time_range_frame = ttk.Frame(time_frame) time_range_frame.pack(fill=tk.X, pady=5) # 获取最小和最大时间 time_col = self.time_col_var.get() min_time = self.df[time_col].min().strftime('%Y-%m-%d %H:%M') max_time = self.df[time_col].max().strftime('%Y-%m-%d %H:%M') ttk.Label(time_range_frame, text="时间范围:").pack(side=tk.LEFT) ttk.Label(time_range_frame, text=f"{min_time} 至 {max_time}", font=("Arial", 9, "bold")).pack(side=tk.LEFT, padx=5) # 2. 切分方式选择 method_frame = ttk.LabelFrame(main_frame, text="切分方式", padding=10) method_frame.pack(fill=tk.X, pady=5) self.divide_method = tk.StringVar(value="ratio") # 按比例切分 ratio_frame = ttk.Frame(method_frame) ratio_frame.pack(fill=tk.X, pady=3) ttk.Radiobutton(ratio_frame, text="按比例切分", variable=self.divide_method, value="ratio").pack(side=tk.LEFT) ratio_subframe = ttk.Frame(ratio_frame) ratio_subframe.pack(side=tk.LEFT, padx=10) ttk.Label(ratio_subframe, text="训练集比例:").pack(side=tk.LEFT) self.train_ratio_var = tk.DoubleVar(value=0.8) ratio_spin = ttk.Spinbox(ratio_subframe, from_=0.1, to=0.9, increment=0.05, width=5, textvariable=self.train_ratio_var) ratio_spin.pack(side=tk.LEFT, padx=5) # 按时间点切分 date_frame = ttk.Frame(method_frame) date_frame.pack(fill=tk.X, pady=3) ttk.Radiobutton(date_frame, text="按时间点切分", variable=self.divide_method, value="date").pack(side=tk.LEFT) date_subframe = ttk.Frame(date_frame) date_subframe.pack(side=tk.LEFT, padx=10) ttk.Label(date_subframe, text="切分时间:").pack(side=tk.LEFT) # 使用日历控件选择日期 self.divide_date_var = tk.StringVar(value=min_time) date_entry = ttk.Entry(date_subframe, textvariable=self.divide_date_var, width=16) date_entry.pack(side=tk.LEFT, padx=5) # 3. 数据集选择 dataset_frame = ttk.LabelFrame(main_frame, text="选择数据集", padding=10) dataset_frame.pack(fill=tk.X, pady=5) self.dataset_var = tk.StringVar(value="train") ttk.Radiobutton(dataset_frame, text="训练集 (切分点之前)", variable=self.dataset_var, value="train").pack(anchor=tk.W) ttk.Radiobutton(dataset_frame, text="测试集 (切分点之后)", variable=self.dataset_var, value="test").pack(anchor=tk.W) ttk.Radiobutton(dataset_frame, text="全部数据 (仅划分,不切分)", variable=self.dataset_var, value="all").pack(anchor=tk.W) # 4. 添加切分标记选项 mark_frame = ttk.LabelFrame(main_frame, text="切分标记", padding=10) mark_frame.pack(fill=tk.X, pady=5) self.mark_division = tk.BooleanVar(value=True) ttk.Checkbutton(mark_frame, text="添加数据集标记列 (train/test)", variable=self.mark_division).pack(anchor=tk.W) # 5. 执行按钮 btn_frame = ttk.Frame(main_frame) btn_frame.pack(fill=tk.X, pady=10) def apply_division(): """应用数据切分""" try: time_col = self.time_col_var.get() # 确保数据按时间排序 self.df = self.df.sort_values(by=time_col) # 计算切分点 if self.divide_method.get() == "ratio": ratio = self.train_ratio_var.get() split_index = int(len(self.df) * ratio) split_time = self.df.iloc[split_index][time_col] else: # 按时间点切分 split_time = pd.to_datetime(self.divide_date_var.get()) split_index = self.df[self.df[time_col] <= split_time].index.max() + 1 # 添加数据集标记列 if self.mark_division.get(): self.df['dataset'] = 'train' self.df.loc[split_index:, 'dataset'] = 'test' # 根据选择获取数据集 dataset_choice = self.dataset_var.get() if dataset_choice == "train": self.df = self.df.iloc[:split_index] result_type = "训练集" elif dataset_choice == "test": self.df = self.df.iloc[split_index:] result_type = "测试集" else: result_type = "全部数据 (已添加标记)" # 更新显示 self.show_preview() divide_window.destroy() self.status_var.set(f"数据切分完成 | {result_type} | 切分点: {split_time.strftime('%Y-%m-%d %H:%M')}") messagebox.showinfo("切分完成", f"大坝渗流数据切分完成\n当前数据集: {result_type}") except Exception as e: messagebox.showerror("切分错误", f"数据切分失败:\n{str(e)}") def preview_division(): """预览切分点""" try: time_col = self.time_col_var.get() if self.divide_method.get() == "ratio": ratio = self.train_ratio_var.get() split_index = int(len(self.df) * ratio) split_time = self.df.iloc[split_index][time_col] else: split_time = pd.to_datetime(self.divide_date_var.get()) split_index = self.df[self.df[time_col] <= split_time].index.max() + 1 train_count = split_index test_count = len(self.df) - split_index messagebox.showinfo("切分预览", f"切分点时间: {split_time.strftime('%Y-%m-%d %H:%M')}\n" f"训练集数据量: {train_count} 行 ({train_count / len(self.df) * 100:.1f}%)\n" f"测试集数据量: {test_count} 行 ({test_count / len(self.df) * 100:.1f}%)") except Exception as e: messagebox.showerror("预览错误", f"切分点预览失败:\n{str(e)}") ttk.Button(btn_frame, text="预览切分点", command=preview_division).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="应用切分", command=apply_division).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="取消", command=divide_window.destroy).pack(side=tk.RIGHT, padx=5) def save_data(self): """保存处理结果""" if self.df is None or self.df.empty: messagebox.showwarning("警告", "没有可保存的数据") return save_path = filedialog.asksaveasfilename( defaultextension=".xlsx", filetypes=[("Excel文件", "*.xlsx"), ("CSV文件", "*.csv")] ) if not save_path: return try: if save_path.endswith('.xlsx'): self.df.to_excel(save_path, index=False) else: self.df.to_csv(save_path, index=False) self.status_var.set(f"文件已保存至: {os.path.basename(save_path)}") messagebox.showinfo("保存成功", f"文件已成功保存至:\n{save_path}") except Exception as e: messagebox.showerror("保存错误", f"保存文件失败:\n{str(e)}") 创建并运行程序 if name == “main”: root = tk.Tk() app = ExcelProcessor(root) root.mainloop() 我是想让你设计成这样的一个窗口格式可以选择excel文件当作训练集和测试集

最新推荐

recommend-type

婚纱摄影公司网络推广人员工作绩效说明.docx

婚纱摄影公司网络推广人员工作绩效说明.docx
recommend-type

公路工程的项目管理分析.doc

公路工程的项目管理分析.doc
recommend-type

2025青海省道路路网矢量数据图层Shp数据最新版下载

2025青海省道路路网矢量数据图层,shp格式,包含多级道路分类属性,路名等属性,包含全省几十万条道路,坐标系为WGS1984坐标系统
recommend-type

项目管理机构配备情况-secret.doc

项目管理机构配备情况-secret.doc
recommend-type

VC图像编程全面资料及程序汇总

【标题】:"精通VC图像编程资料全览" 【知识点】: VC即Visual C++,是微软公司推出的一个集成开发环境(IDE),专门用于C++语言的开发。VC图像编程涉及到如何在VC++开发环境中处理和操作图像。在VC图像编程中,开发者通常会使用到Windows API中的GDI(图形设备接口)或GDI+来进行图形绘制,以及DirectX中的Direct2D或DirectDraw进行更高级的图形处理。 1. GDI(图形设备接口): - GDI是Windows操作系统提供的一套应用程序接口,它允许应用程序通过设备无关的方式绘制图形。 - 在VC图像编程中,主要使用CDC类(设备上下文类)来调用GDI函数进行绘制,比如绘制线条、填充颜色、显示文本等。 - CDC类提供了很多函数,比如`MoveTo`、`LineTo`、`Rectangle`、`Ellipse`、`Polygon`等,用于绘制基本的图形。 - 对于图像处理,可以使用`StretchBlt`、`BitBlt`、`TransparentBlt`等函数进行图像的位块传输。 2. GDI+: - GDI+是GDI的后继技术,提供了更丰富的图形处理功能。 - GDI+通过使用`Graphics`类来提供图像的绘制、文本的渲染、图像的处理和颜色管理等功能。 - GDI+引入了对矢量图形、渐变色、复杂的文本格式和坐标空间等更高级的图形处理功能。 - `Image`类是GDI+中用于图像操作的基础类,通过它可以进行图像的加载、保存、旋转、缩放等操作。 3. DirectX: - DirectX是微软推出的一系列API集合,用于在Windows平台上进行高性能多媒体编程。 - DirectX中的Direct2D是用于硬件加速的二维图形API,专门用于UI元素和简单的图形渲染。 - DirectDraw主要用于硬件加速的位图操作,比如全屏游戏开发中的画面渲染。 4. 位图操作: - 在VC图像编程中,位图操作是一个重要的部分。需要了解如何加载、保存和处理位图(BMP)文件。 - 可以使用位图文件格式的解析,来访问位图的像素数据,进行像素级别的图像处理和修改。 5. 高级图像处理技术: - 包括图像滤镜、图像转换、图像压缩和解压缩技术。 - 需要掌握一些图像处理算法,比如卷积、FFT(快速傅里叶变换)、DCT(离散余弦变换)等。 - 了解图像的色彩空间转换,比如RGB到YUV的转换,这在视频处理中非常重要。 6. 图像库的使用: - 除了直接使用API进行图像处理之外,还可以使用开源的图像处理库,如OpenCV。 - OpenCV是一个跨平台的计算机视觉和机器学习软件库,它提供了很多高级的图像处理功能。 【压缩包子文件的文件名称列表】: VC++ 文件名称列表显示为"VC++",这表明文件包中可能包含了Visual C++的项目、源代码文件、动态链接库(DLLs)、编译器设置、链接器设置等。如果要使用这些文件进行VC图像编程,需要确保Visual C++开发环境已经安装并且配置好,同时需要安装好所有依赖的库和工具。 要开始VC图像编程,开发者需要具备C++编程基础,熟悉Windows编程概念,并且对图形学有一定的了解。掌握VC图像编程技巧,对于进行桌面应用程序开发、图像处理软件开发以及游戏开发等都是至关重要的。
recommend-type

Pokemmo响应速度翻倍:多线程处理的高级技巧

# 摘要 多线程处理是提高软件并发性能和响应速度的关键技术,本文从基础概念与优势出发,深入探讨了多线程的实现机制,包括线程模型、调度算法、编程关键技术、线程安全性最佳实践、死锁预防与处理等方面。通
recommend-type

人名列表滚动抽奖

<think>嗯,用户想实现一个滚动抽奖功能,需要前端动画效果和随机选择逻辑。首先,我得考虑前端怎么实现滚动效果。可能用CSS动画或者JavaScript的requestAnimationFrame?比如,使用CSS的@keyframes来控制位移,或者用JS动态更新样式。然后,随机选择算法,可能需要确保公平性,比如用Fisher-Yates洗牌算法,或者用Math.random()来生成随机索引。然后,用户可能需要平滑的滚动动画,比如先快速滚动,然后逐渐减速,最后停在选中的人名上。这可能需要设置定时器,逐步改变位置,或者使用CSS过渡效果。另外,还要考虑性能,避免页面卡顿,可能需要使用硬件加
recommend-type

一站式JSF开发环境:即解压即用JAR包

标题:“jsf开发完整JAR包”所指的知识点: 1. JSF全称JavaServer Faces,是Java EE(现EE4J)规范之一,用于简化Java Web应用中基于组件的用户界面构建。JSF提供了一种模型-视图-控制器(MVC)架构的实现,使得开发者可以将业务逻辑与页面表示分离。 2. “开发完整包”意味着这个JAR包包含了JSF开发所需的所有类库和资源文件。通常来说,一个完整的JSF包会包含核心的JSF库,以及一些可选的扩展库,例如PrimeFaces、RichFaces等,这些扩展库提供了额外的用户界面组件。 3. 在一个项目中使用JSF,开发者无需单独添加每个必要的JAR文件到项目的构建路径中。因为打包成一个完整的JAR包后,所有这些依赖都被整合在一起,极大地方便了开发者的部署工作。 4. “解压之后就可以直接导入工程中使用”表明这个JAR包是一个可执行的归档文件,可能是一个EAR包或者一个可直接部署的Java应用包。解压后,开发者只需将其内容导入到他们的IDE(如Eclipse或IntelliJ IDEA)中,或者将其放置在Web应用服务器的正确目录下,就可以立即进行开发。 描述中所指的知识点: 1. “解压之后就可以直接导入工程中使用”说明这个JAR包是预先配置好的,它可能包含了所有必要的配置文件,例如web.xml、faces-config.xml等,这些文件是JSF项目运行所必需的。 2. 直接使用意味着减少了开发者配置环境和处理依赖的时间,有助于提高开发效率。 标签“jsf jar包”所指的知识点: 1. 标签指明了JAR包的内容是专门针对JSF框架的。因此,这个JAR包包含了JSF规范所定义的API以及可能包含的具体实现,比如Mojarra或MyFaces。 2. “jar包”是一种Java平台的归档文件格式,用于聚合多个文件到一个文件中。在JSF开发中,JAR文件经常被用来打包和分发库或应用程序。 文件名称列表“jsf”所指的知识点: 1. “jsf”文件名可能意味着这是JSF开发的核心库,它应该包含了所有核心的JavaServer Faces类文件以及资源文件。 2. 如果是使用特定版本的JSF,例如“jsf-2.2.jar”,则表明文件内包含了对应版本的JSF实现。这种情况下,开发者必须确认他们所使用的Web服务器或应用程序服务器支持该版本的JSF。 3. 文件名称也可能是“jsf-components.jar”、“jsf-impl.jar”等,表明这个JAR包是JSF的一个子模块或特定功能组件。例如,“jsf-components.jar”可能包含了一系列用于在JSF应用中使用的自定义组件。 4. 对于开发者而言,了解文件名称中所蕴含的信息非常重要,因为这将决定他们需要下载哪些JAR包来满足特定项目的需求。 综合以上信息,开发者在使用JSF进行Java Web应用开发时,会通过一个预先配置好的JAR包来快速地搭建和启动项目。这样做不仅简化了项目初始化的过程,也使得开发者能够更加聚焦于业务逻辑的实现和界面设计,而不必深究底层框架配置的细节。
recommend-type

Pokemmo内存优化揭秘:专家教你如何降低50%资源消耗

# 摘要 本文综述了Pokemmo游戏的内存优化方法,从内存管理基础出发,探讨内存使用效率的影响因素,并介绍了性能监控与分析工具。在内存优化实践技巧章节中,详细讨论了代码层面的优化、数据结构和算法选择对内存效率的影响,并通过案例分析展示了实际的优化过程。针对Pokemmo游戏特点,分析了内存消耗特性并提出了特定优化技术。最后,本文展望了未来内存管理技术的发展方向,以及游戏开发中面临的新挑战,为Pokemmo及类似游戏提供了优化建议。 # 关键字 内存优化;内存管理;性能监控;数据结构;算法效率;游戏开发 参考资源链接:[Pokemmo必备资源包:四种ROM与汉化补丁](https://we
recommend-type

直接访问子路由是吧

<think>我们正在使用Vue2,因此需要参考VueRouterv3的文档(因为Vue2对应VueRouterv3,Vue3对应VueRouterv4)。用户的问题是:如何配置路由以支持直接访问子路由?即,在Vue2中,我们希望直接通过URL访问嵌套的子路由(例如:/parent/child),而不仅仅是先访问父路由再导航到子路由。根据之前的回答和引用,我们已经知道:1.在父路由的配置中,使用`children`数组来定义子路由。2.子路由的`path`不能以斜杠开头(例如:'child'而不是'/child'),这样它就会基于父路由的路径进行拼接。3.在父组件的模板中放置`<router-