最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python實現(xiàn)Exce格式化批處理工具

 更新時間:2025年04月07日 14:38:22   作者:探客白澤  
原始Excel數(shù)據(jù)常常存在格式不統(tǒng)一、空值、重復數(shù)據(jù)等問題,影響數(shù)據(jù)的準確性和可用性,所以本文就來使用Python編寫一個Excel數(shù)據(jù)清洗工具,有需要的小伙伴可以參考一下

1. 概述

在數(shù)據(jù)分析、報表整理、數(shù)據(jù)庫管理等工作中,數(shù)據(jù)清洗是不可或缺的一步。原始Excel數(shù)據(jù)常常存在格式不統(tǒng)一、空值、重復數(shù)據(jù)等問題,影響數(shù)據(jù)的準確性和可用性。本篇文章將詳細介紹一款高效的Excel數(shù)據(jù)清洗工具,幫助您輕松處理雜亂數(shù)據(jù),提高數(shù)據(jù)質量。

2. 功能使用

基本操作流程

使用本工具進行數(shù)據(jù)清洗的操作流程如下:

  • 打開文件:點擊"瀏覽"按鈕,或使用菜單欄"文件 > 打開"選擇需要處理的Excel文件。
  • 數(shù)據(jù)清洗:在左側工具面板選擇需要的清洗操作,例如刪除重復行、格式化日期等。
  • 預覽結果:右側區(qū)域實時顯示數(shù)據(jù)變化,確保清洗效果符合預期。
  • 保存文件:點擊"保存"按鈕,或使用菜單欄"文件 > 保存",將處理后的文件存儲。

3. 主要功能說明

1. 刪除重復行

作用:刪除數(shù)據(jù)表中完全相同的行,確保數(shù)據(jù)唯一性。

2. 刪除空行

作用:清除所有值均為空的行,避免無效數(shù)據(jù)干擾分析。

3. 去除空格

作用:移除文本字段中的首尾空格,防止隱藏字符影響計算。

4. 統(tǒng)一大小寫

作用:可選擇轉換為小寫、大寫或首字母大寫,以確保數(shù)據(jù)格式一致。

5. 數(shù)值格式化

作用:統(tǒng)一數(shù)值的小數(shù)位數(shù)(默認保留2位),保證數(shù)據(jù)規(guī)范。

6. 日期格式化

作用:提供多種日期格式選項,避免因格式混亂導致的數(shù)據(jù)處理錯誤。

7. 刪除特殊字符

作用:去除文本中的標點符號、特殊字符,適用于純文本數(shù)據(jù)處理。

8. 填充空值

作用:支持多種空值填充方式(平均值、中位數(shù)、眾數(shù)等),提高數(shù)據(jù)完整性。

4. 適用場景

4.1 典型使用場景

數(shù)據(jù)預處理:在進行數(shù)據(jù)分析前,先對原始數(shù)據(jù)進行標準化處理。

報表整理:整合不同來源的數(shù)據(jù),保證格式統(tǒng)一。

數(shù)據(jù)庫導入準備:清理Excel數(shù)據(jù),使其符合數(shù)據(jù)庫字段要求。

數(shù)據(jù)遷移:在不同系統(tǒng)之間轉移數(shù)據(jù)時,保證格式一致。

日常辦公:快速整理雜亂的Excel表格,提高工作效率。

4.2 適用人群

數(shù)據(jù)分析師

財務/行政人員

市場研究人員

數(shù)據(jù)庫管理員

任何需要處理Excel數(shù)據(jù)的辦公人員

5. 注意事項

5.1 使用前注意事項

備份原始數(shù)據(jù):建議在處理前保存一份原始文件,以免數(shù)據(jù)丟失。

數(shù)據(jù)量限制:預覽功能僅顯示前100行,但清洗操作會應用于所有數(shù)據(jù)。

文件格式:支持.xlsx和.xls格式,建議使用.xlsx以獲得更好的兼容性。

5.2 操作注意事項

撤銷功能:當前版本不支持撤銷操作,請謹慎執(zhí)行。

特殊字符處理:刪除特殊字符可能影響某些編碼數(shù)據(jù),請?zhí)崆皺z查。

日期識別:自動識別日期列可能不夠準確,建議手動確認。

數(shù)值處理:非數(shù)值字段嘗試數(shù)值格式化可能導致錯誤。

6.系統(tǒng)要求

本工具依賴Python環(huán)境,使用以下庫來處理數(shù)據(jù):

  • Python 3.6+
  • pandas(數(shù)據(jù)處理核心庫)
  • numpy(數(shù)值運算支持)
  • openpyxl(用于Excel文件操作)
  • tkinter(用于GUI界面,Python自帶)
  • matplotlib(可視化功能支持)

7.高級技巧

大型文件處理:對于超過10MB的文件,處理可能較慢,建議分批處理。

數(shù)據(jù)可視化:工具提供基本的可視化功能,適用于數(shù)值型數(shù)據(jù)分析。

快速數(shù)據(jù)分析:可查看基本統(tǒng)計信息,如均值、中位數(shù)、方差等,幫助快速了解數(shù)據(jù)分布。

8.相關源碼

import pandas as pd
import numpy as np
from tkinter import *
from tkinter import ttk, filedialog, messagebox
import os
from tkinter.scrolledtext import ScrolledText
import threading
from queue import Queue
import logging
from datetime import datetime
 
# 配置日志
logging.basicConfig(
    filename='excel_cleaner.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
 
# 模擬 DataHandler, ColumnSelector, ParameterDialog 類
class DataHandler:
    def __init__(self):
        self.df = None
        self.operation_history = []
        self.redo_history = []
 
    def load_excel(self, file_path):
        self.df = pd.read_excel(file_path)
        return self.df
 
    def save_excel(self, file_path):
        self.df.to_excel(file_path, index=False)
 
    def get_statistics(self):
        return {
            'row_count': len(self.df),
            'column_count': len(self.df.columns)
        }
 
    def get_column_types(self):
        return self.df.dtypes
 
    def remove_spaces(self, columns):
        for col in columns:
            if self.df[col].dtype == object:
                self.df[col] = self.df[col].str.strip()
        return self.df
 
    def normalize_case(self, case_type, columns):
        for col in columns:
            if self.df[col].dtype == object:
                if case_type == 'lower':
                    self.df[col] = self.df[col].str.lower()
                elif case_type == 'upper':
                    self.df[col] = self.df[col].str.upper()
                elif case_type == 'title':
                    self.df[col] = self.df[col].str.title()
        return self.df
 
    def format_numbers(self, decimal_places, columns):
        for col in columns:
            if pd.api.types.is_numeric_dtype(self.df[col]):
                self.df[col] = self.df[col].round(decimal_places)
        return self.df
 
    def format_dates(self, date_format, columns):
        for col in columns:
            if pd.api.types.is_datetime64_any_dtype(self.df[col]):
                self.df[col] = self.df[col].dt.strftime(date_format)
        return self.df
 
    def remove_special_chars(self, pattern, columns):
        for col in columns:
            if self.df[col].dtype == object:
                self.df[col] = self.df[col].str.replace(pattern, '', regex=True)
        return self.df
 
    def fill_empty_values(self, method, value=None, columns=None):
        if columns is None:
            columns = self.df.columns
        for col in columns:
            if method == 'value':
                self.df[col].fillna(value, inplace=True)
            elif method == 'mean':
                self.df[col].fillna(self.df[col].mean(), inplace=True)
            elif method == 'median':
                self.df[col].fillna(self.df[col].median(), inplace=True)
            elif method == 'mode':
                self.df[col].fillna(self.df[col].mode()[0], inplace=True)
            elif method == 'ffill':
                self.df[col].fillna(method='ffill', inplace=True)
            elif method == 'bfill':
                self.df[col].fillna(method='bfill', inplace=True)
        return self.df
 
 
class ColumnSelector:
    def __init__(self, parent, columns, column_types, title, callback):
        self.callback = callback
        self.selected_columns = []
 
        self.window = Toplevel(parent)
        self.window.title(title)
 
        ttk.Label(self.window, text="選擇列:").pack(pady=10)
 
        self.listbox = Listbox(self.window, selectmode=MULTIPLE)
        for col in columns:
            self.listbox.insert(END, col)
        self.listbox.pack(fill=BOTH, expand=True, padx=10, pady=10)
 
        button_frame = ttk.Frame(self.window)
        button_frame.pack(fill=X, padx=10, pady=10)
 
        ttk.Button(button_frame, text="確定", command=self.on_confirm).pack(side=LEFT, padx=10)
        ttk.Button(button_frame, text="取消", command=self.window.destroy).pack(side=LEFT)
 
    def on_confirm(self):
        self.selected_columns = [self.listbox.get(i) for i in self.listbox.curselection()]
        self.callback(self.selected_columns)
        self.window.destroy()
 
 
class ParameterDialog:
    def __init__(self, parent, params, title, callback):
        self.callback = callback
        self.params = params
        self.values = {}
 
        self.window = Toplevel(parent)
        self.window.title(title)
 
        for param_name, param_info in params.items():
            ttk.Label(self.window, text=param_info['label']).pack(pady=5)
            if param_info['type'] == 'choice':
                var = StringVar()
                var.set(param_info['default'])
                ttk.Combobox(self.window, textvariable=var, values=param_info['choices']).pack(fill=X, padx=10)
                self.values[param_name] = var
            elif param_info['type'] == 'int':
                var = IntVar()
                var.set(param_info['default'])
                ttk.Spinbox(self.window, from_=param_info['min'], to=param_info['max'], textvariable=var).pack(fill=X, padx=10)
                self.values[param_name] = var
            elif param_info['type'] == 'str':
                var = StringVar()
                var.set(param_info['default'])
                ttk.Entry(self.window, textvariable=var).pack(fill=X, padx=10)
                self.values[param_name] = var
 
        button_frame = ttk.Frame(self.window)
        button_frame.pack(fill=X, padx=10, pady=10)
 
        ttk.Button(button_frame, text="確定", command=self.on_confirm).pack(side=LEFT, padx=10)
        ttk.Button(button_frame, text="取消", command=self.window.destroy).pack(side=LEFT)
 
    def on_confirm(self):
        result = {param_name: var.get() for param_name, var in self.values.items()}
        self.callback(result)
        self.window.destroy()
 
 
class ExcelCleaner:
    def __init__(self):
        self.window = Tk()
        self.window.title("Excel數(shù)據(jù)格式化批處理工具")
        self.window.geometry("1000x800")
        self.window.configure(bg='#f0f0f0')
 
        # 初始化數(shù)據(jù)處理器
        self.data_handler = DataHandler()
        self.processing_queue = Queue()
 
        # 設置樣式
        self.setup_styles()
 
        # 創(chuàng)建菜單欄
        self.create_menu()
 
        # 創(chuàng)建主框架
        main_frame = ttk.Frame(self.window)
        main_frame.pack(fill=BOTH, expand=True, padx=10, pady=5)
 
        # 左側工具面板
        left_panel = ttk.LabelFrame(main_frame, text="工具面板", padding=10)
        left_panel.pack(side=LEFT, fill=Y, padx=5, pady=5)
 
        # 文件操作區(qū)域
        self.create_file_frame(left_panel)
 
        # 清洗操作區(qū)域
        self.create_clean_frame(left_panel)
 
        # 右側主要內容區(qū)域
        right_panel = ttk.Frame(main_frame)
        right_panel.pack(side=LEFT, fill=BOTH, expand=True, padx=5)
 
        # 預覽區(qū)域
        self.create_preview_frame(right_panel)
 
        # 狀態(tài)欄
        self.create_status_bar()
 
        # 進度條
        self.create_progress_bar()
 
        # 綁定快捷鍵
        self.bind_shortcuts()
 
    def setup_styles(self):
        style = ttk.Style()
        style.theme_use('clam')
 
        # 配置按鈕樣式
        style.configure(
            "Tool.TButton",
            padding=5,
            font=('微軟雅黑', 10),
            background='#e1e1e1',
            foreground='#333333'
        )
 
        # 配置標簽樣式
        style.configure(
            "Title.TLabel",
            font=('微軟雅黑', 12, 'bold'),
            background='#f0f0f0',
            foreground='#333333'
        )
 
        # 配置框架樣式
        style.configure(
            "Card.TLabelframe",
            background='#ffffff',
            padding=10
        )
 
        # 配置樹形視圖樣式
        style.configure(
            "Preview.Treeview",
            font=('微軟雅黑', 10),
            rowheight=25
        )
 
        # 配置進度條樣式
        style.configure(
            "Progress.Horizontal.TProgressbar",
            troughcolor='#f0f0f0',
            background='#4CAF50',
            thickness=10
        )
 
    def create_progress_bar(self):
        self.progress_var = DoubleVar()
        self.progress_bar = ttk.Progressbar(
            self.window,
            style="Progress.Horizontal.TProgressbar",
            variable=self.progress_var,
            maximum=100
        )
        self.progress_bar.pack(fill=X, padx=5, pady=2)
 
    def bind_shortcuts(self):
        self.window.bind('<Control-o>', lambda e: self.select_file())
        self.window.bind('<Control-s>', lambda e: self.save_file())
        self.window.bind('<Control-z>', lambda e: self.undo())
        self.window.bind('<Control-y>', lambda e: self.redo())
        self.window.bind('<F1>', lambda e: self.show_help())
 
    def process_in_background(self, func, *args, **kwargs):
        """在后臺線程中處理耗時操作"""
        def wrapper():
            try:
                self.progress_var.set(0)
                self.status_var.set("正在處理...")
                self.window.update()
 
                # 執(zhí)行操作
                result = func(*args, **kwargs)
 
                # 更新UI
                self.window.after(0, self.update_ui_after_processing, result)
 
            except Exception as e:
                logging.error(f"處理錯誤: {str(e)}")
                self.window.after(0, self.show_error, str(e))
            finally:
                self.window.after(0, self.progress_var.set, 100)
                self.window.after(0, self.status_var.set, "處理完成")
 
        # 啟動后臺線程
        thread = threading.Thread(target=wrapper)
        thread.daemon = True
        thread.start()
 
    def update_ui_after_processing(self, result):
        """處理完成后更新UI"""
        if isinstance(result, tuple):
            self.data_handler.df = result[0]
            if len(result) > 1:
                removed_rows = result[1]
                self.status_var.set(f"已刪除 {removed_rows} 行數(shù)據(jù)")
        elif isinstance(result, pd.DataFrame):
            self.data_handler.df = result
 
        if result is not None:
            self.update_preview()
 
    def show_error(self, error_msg):
        """顯示錯誤消息"""
        messagebox.showerror("錯誤", f"處理過程中出現(xiàn)錯誤:{error_msg}")
        self.status_var.set("處理失敗")
 
    def select_file(self):
        file_path = filedialog.askopenfilename(
            filetypes=[("Excel files", "*.xlsx *.xls")]
        )
        if file_path:
            self.process_in_background(self.data_handler.load_excel, file_path)
 
    def save_file(self):
        if self.data_handler.df is not None:
            file_path = filedialog.asksaveasfilename(
                defaultextension=".xlsx",
                filetypes=[("Excel files", "*.xlsx")]
            )
            if file_path:
                self.process_in_background(self.data_handler.save_excel, file_path)
 
    def undo(self):
        """撤銷上一步操作"""
        if self.data_handler.operation_history:
            last_operation = self.data_handler.operation_history.pop()
            self.data_handler.df = last_operation['previous_state'].copy()
            self.update_preview()
            self.status_var.set("已撤銷上一步操作")
 
    def redo(self):
        """重做上一步操作"""
        if hasattr(self.data_handler, 'redo_history') and self.data_handler.redo_history:
            last_operation = self.data_handler.redo_history.pop()
            self.data_handler.df = last_operation['next_state'].copy()
            self.data_handler.operation_history.append(last_operation)
            self.update_preview()
            self.status_var.set("已重做上一步操作")
 
    def add_operation_to_history(self, operation_name, previous_state, next_state):
        """添加操作到歷史記錄"""
        self.data_handler.operation_history.append({
            'name': operation_name,
            'previous_state': previous_state.copy(),
            'next_state': next_state.copy()
        })
        # 清空重做歷史
        if hasattr(self.data_handler, 'redo_history'):
            self.data_handler.redo_history.clear()
 
    def remove_duplicates(self):
        if self.data_handler.df is not None:
            previous_state = self.data_handler.df.copy()
            self.data_handler.df = self.data_handler.df.drop_duplicates()
            removed_rows = len(previous_state) - len(self.data_handler.df)
            self.add_operation_to_history("刪除重復行", previous_state, self.data_handler.df.copy())
            self.update_preview()
            self.status_var.set(f"已刪除 {removed_rows} 行重復數(shù)據(jù)")
 
    def remove_empty_rows(self):
        if self.data_handler.df is not None:
            previous_state = self.data_handler.df.copy()
            self.data_handler.df = self.data_handler.df.dropna(how='all')
            removed_rows = len(previous_state) - len(self.data_handler.df)
            self.add_operation_to_history("刪除空行", previous_state, self.data_handler.df.copy())
            self.update_preview()
            self.status_var.set(f"已刪除 {removed_rows} 行空數(shù)據(jù)")
 
    def remove_spaces(self):
        if self.data_handler.df is not None:
            def on_columns_selected(columns):
                self.process_in_background(
                    self.data_handler.remove_spaces,
                    columns=columns
                )
 
            ColumnSelector(
                self.window,
                list(self.data_handler.df.columns),
                self.data_handler.get_column_types(),
                title="選擇要去除空格的列",
                callback=on_columns_selected
            )
 
    def normalize_case(self):
        if self.data_handler.df is not None:
            def on_params_set(params):
                def on_columns_selected(columns):
                    self.process_in_background(
                        self.data_handler.normalize_case,
                        case_type=params["case_type"],
                        columns=columns
                    )
 
                ColumnSelector(
                    self.window,
                    list(self.data_handler.df.columns),
                    self.data_handler.get_column_types(),
                    title="選擇要統(tǒng)一大小寫的列",
                    callback=on_columns_selected
                )
 
            params = {
                "case_type": {
                    "type": "choice",
                    "label": "大小寫格式",
                    "default": "lower",
                    "choices": ["lower", "upper", "title"]
                }
            }
 
            ParameterDialog(
                self.window,
                params,
                title="選擇大小寫格式",
                callback=on_params_set
            )
 
    def format_numbers(self):
        if self.data_handler.df is not None:
            def on_params_set(params):
                def on_columns_selected(columns):
                    self.process_in_background(
                        self.data_handler.format_numbers,
                        decimal_places=params["decimal_places"],
                        columns=columns
                    )
 
                ColumnSelector(
                    self.window,
                    list(self.data_handler.df.columns),
                    self.data_handler.get_column_types(),
                    title="選擇要格式化的數(shù)值列",
                    callback=on_columns_selected
                )
 
            params = {
                "decimal_places": {
                    "type": "int",
                    "label": "小數(shù)位數(shù)",
                    "default": 2,
                    "min": 0,
                    "max": 10
                }
            }
 
            ParameterDialog(
                self.window,
                params,
                title="設置數(shù)值格式",
                callback=on_params_set
            )
 
    def format_dates(self):
        if self.data_handler.df is not None:
            def on_params_set(params):
                def on_columns_selected(columns):
                    self.process_in_background(
                        self.data_handler.format_dates,
                        date_format=params["date_format"],
                        columns=columns
                    )
 
                ColumnSelector(
                    self.window,
                    list(self.data_handler.df.columns),
                    self.data_handler.get_column_types(),
                    title="選擇要格式化的日期列",
                    callback=on_columns_selected
                )
 
            params = {
                "date_format": {
                    "type": "choice",
                    "label": "日期格式",
                    "default": "%Y-%m-%d",
                    "choices": [
                        "%Y-%m-%d",
                        "%Y/%m/%d",
                        "%d-%m-%Y",
                        "%m/%d/%Y"
                    ]
                }
            }
 
            ParameterDialog(
                self.window,
                params,
                title="選擇日期格式",
                callback=on_params_set
            )
 
    def remove_special_chars(self):
        if self.data_handler.df is not None:
            def on_params_set(params):
                def on_columns_selected(columns):
                    self.process_in_background(
                        self.data_handler.remove_special_chars,
                        pattern=params["pattern"],
                        columns=columns
                    )
 
                ColumnSelector(
                    self.window,
                    list(self.data_handler.df.columns),
                    self.data_handler.get_column_types(),
                    title="選擇要處理的列",
                    callback=on_columns_selected
                )
 
            params = {
                "pattern": {
                    "type": "str",
                    "label": "正則表達式",
                    "default": r'[^\w\s]'
                }
            }
 
            ParameterDialog(
                self.window,
                params,
                title="設置正則表達式",
                callback=on_params_set
            )
 
    def fill_empty_values(self):
        if self.data_handler.df is not None:
            def on_params_set(params):
                def on_columns_selected(columns):
                    value = params.get("value")
                    if params["method"] == "value" and value:
                        try:
                            # 嘗試轉換為數(shù)值
                            value = float(value) if '.' in value else int(value)
                        except ValueError:
                            pass
 
                    self.process_in_background(
                        self.data_handler.fill_empty_values,
                        method=params["method"],
                        value=value,
                        columns=columns
                    )
 
                ColumnSelector(
                    self.window,
                    list(self.data_handler.df.columns),
                    self.data_handler.get_column_types(),
                    title="選擇要填充的列",
                    callback=on_columns_selected
                )
 
            params = {
                "method": {
                    "type": "choice",
                    "label": "填充方式",
                    "default": "mean",
                    "choices": ["mean", "median", "mode", "ffill", "bfill", "value"]
                },
                "value": {
                    "type": "str",
                    "label": "填充值",
                    "default": ""
                }
            }
 
            ParameterDialog(
                self.window,
                params,
                title="選擇填充方式",
                callback=on_params_set
            )
 
    def analyze_data(self):
        if self.data_handler.df is not None:
            analysis_window = Toplevel(self.window)
            analysis_window.title("數(shù)據(jù)分析")
            analysis_window.geometry("600x400")
 
            stats_text = ScrolledText(analysis_window, wrap=WORD, width=70, height=20)
            stats_text.pack(padx=10, pady=10, fill=BOTH, expand=True)
 
            stats = []
            stats.append("數(shù)據(jù)基本信息:")
            stats.append("-" * 50)
            stats.append(f"總行數(shù):{len(self.data_handler.df)}")
            stats.append(f"總列數(shù):{len(self.data_handler.df.columns)}")
            stats.append("\n數(shù)值列統(tǒng)計:")
            stats.append("-" * 50)
 
            numeric_stats = self.data_handler.df.describe()
            stats.append(str(numeric_stats))
 
            stats.append("\n空值統(tǒng)計:")
            stats.append("-" * 50)
            null_counts = self.data_handler.df.isnull().sum()
            stats.append(str(null_counts))
 
            stats_text.insert(END, "\n".join(stats))
            stats_text.configure(state='disabled')
 
    def visualize_data(self):
        if self.data_handler.df is not None:
            try:
                import matplotlib.pyplot as plt
                from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
 
                # 設置中文字體
                plt.rcParams['font.sans-serif'] = ['SimHei']  # 用來正常顯示中文標簽
                plt.rcParams['axes.unicode_minus'] = False  # 用來正常顯示負號
 
                viz_window = Toplevel(self.window)
                viz_window.title("數(shù)據(jù)可視化")
                viz_window.geometry("800x600")
 
                options_frame = ttk.Frame(viz_window)
                options_frame.pack(fill=X, padx=10, pady=5)
 
                ttk.Label(options_frame, text="圖表類型:").pack(side=LEFT)
                chart_type = StringVar(value="bar")
                ttk.Radiobutton(options_frame, text="柱狀圖", variable=chart_type, value="bar").pack(side=LEFT)
                ttk.Radiobutton(options_frame, text="折線圖", variable=chart_type, value="line").pack(side=LEFT)
                ttk.Radiobutton(options_frame, text="散點圖", variable=chart_type, value="scatter").pack(side=LEFT)
 
                # 添加列選擇
                ttk.Label(options_frame, text="  選擇列:").pack(side=LEFT)
                column_var = StringVar()
                numeric_columns = list(self.data_handler.df.select_dtypes(include=[np.number]).columns)
                if not numeric_columns:
                    messagebox.showwarning("警告", "沒有可用的數(shù)值列進行可視化")
                    return
                column_combo = ttk.Combobox(options_frame, textvariable=column_var, values=numeric_columns)
                column_combo.pack(side=LEFT)
                column_combo.set(numeric_columns[0])
 
                fig, ax = plt.subplots(figsize=(10, 6))
                canvas = FigureCanvasTkAgg(fig, master=viz_window)
                canvas.get_tk_widget().pack(fill=BOTH, expand=True, padx=10, pady=5)
 
                def update_chart():
                    try:
                        ax.clear()
                        chart_style = chart_type.get()
                        selected_column = column_var.get()
 
                        if not selected_column:
                            messagebox.showwarning("警告", "請選擇要可視化的列")
                            return
 
                        if chart_style == "bar":
                            self.data_handler.df[selected_column].plot(kind='bar', ax=ax)
                            ax.set_title(f"{selected_column} 柱狀圖")
                        elif chart_style == "line":
                            self.data_handler.df[selected_column].plot(kind='line', ax=ax)
                            ax.set_title(f"{selected_column} 折線圖")
                        else:  # scatter
                            if len(numeric_columns) >= 2:
                                x_col = selected_column
                                y_col = next(col for col in numeric_columns if col != x_col)
                                self.data_handler.df.plot(kind='scatter', x=x_col, y=y_col, ax=ax)
                                ax.set_title(f"{x_col} vs {y_col} 散點圖")
                            else:
                                messagebox.showwarning("警告", "需要至少兩個數(shù)值列才能創(chuàng)建散點圖")
                                return
 
                        plt.tight_layout()
                        canvas.draw()
                    except Exception as e:
                        messagebox.showerror("錯誤", f"繪圖時發(fā)生錯誤:{str(e)}")
 
                ttk.Button(options_frame, text="更新圖表", command=update_chart).pack(side=LEFT, padx=10)
                update_chart()
 
            except ImportError:
                messagebox.showwarning("警告", "請安裝matplotlib庫以使用可視化功能")
 
    def run(self):
        self.window.mainloop()
 
    def create_menu(self):
        menubar = Menu(self.window)
        self.window.config(menu=menubar)
 
        # 文件菜單
        file_menu = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="文件", menu=file_menu)
        file_menu.add_command(label="打開 (Ctrl+O)", command=self.select_file)
        file_menu.add_command(label="保存 (Ctrl+S)", command=self.save_file)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.window.quit)
 
        # 編輯菜單
        edit_menu = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="編輯", menu=edit_menu)
        edit_menu.add_command(label="撤銷 (Ctrl+Z)", command=self.undo)
        edit_menu.add_command(label="重做 (Ctrl+Y)", command=self.redo)
 
        # 視圖菜單
        view_menu = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="視圖", menu=view_menu)
        view_menu.add_checkbutton(label="顯示狀態(tài)欄", command=self.toggle_status_bar)
 
        # 幫助菜單
        help_menu = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="幫助", menu=help_menu)
        help_menu.add_command(label="使用說明 (F1)", command=self.show_help)
        help_menu.add_command(label="關于", command=self.show_about)
 
    def create_file_frame(self, parent):
        file_frame = ttk.LabelFrame(parent, text="文件操作", padding=10, style="Card.TLabelframe")
        file_frame.pack(fill=X, pady=(0, 10))
 
        # 文件選擇
        self.file_path = StringVar()
        ttk.Label(file_frame, text="Excel文件:", style="Title.TLabel").pack(anchor=W)
        ttk.Entry(file_frame, textvariable=self.file_path, width=30).pack(fill=X, pady=5)
 
        button_frame = ttk.Frame(file_frame)
        button_frame.pack(fill=X)
 
        ttk.Button(button_frame, text="瀏覽", command=self.select_file, style="Tool.TButton").pack(side=LEFT, padx=2)
        ttk.Button(button_frame, text="保存", command=self.save_file, style="Tool.TButton").pack(side=LEFT, padx=2)
 
    def create_clean_frame(self, parent):
        clean_frame = ttk.LabelFrame(parent, text="數(shù)據(jù)清洗", padding=10, style="Card.TLabelframe")
        clean_frame.pack(fill=BOTH, expand=True)
 
        operations = [
            ("刪除重復行", self.remove_duplicates),
            ("刪除空行", self.remove_empty_rows),
            ("去除空格", self.remove_spaces),
            ("統(tǒng)一大小寫", self.normalize_case),
            ("數(shù)值格式化", self.format_numbers),
            ("日期格式化", self.format_dates),
            ("刪除特殊字符", self.remove_special_chars),
            ("填充空值", self.fill_empty_values),
            ("數(shù)據(jù)分析", self.analyze_data),
            ("數(shù)據(jù)可視化", self.visualize_data)
        ]
 
        for text, command in operations:
            btn = ttk.Button(clean_frame, text=text, command=command, style="Tool.TButton")
            btn.pack(fill=X, pady=2)
 
    def create_preview_frame(self, parent):
        preview_frame = ttk.LabelFrame(parent, text="數(shù)據(jù)預覽", padding=10, style="Card.TLabelframe")
        preview_frame.pack(fill=BOTH, expand=True)
 
        # 創(chuàng)建帶滾動條的樹形視圖
        tree_frame = ttk.Frame(preview_frame)
        tree_frame.pack(fill=BOTH, expand=True)
 
        # 創(chuàng)建水平滾動條
        h_scrollbar = ttk.Scrollbar(tree_frame, orient=HORIZONTAL)
        h_scrollbar.pack(side=BOTTOM, fill=X)
 
        # 創(chuàng)建垂直滾動條
        v_scrollbar = ttk.Scrollbar(tree_frame)
        v_scrollbar.pack(side=RIGHT, fill=Y)
 
        # 創(chuàng)建樹形視圖
        self.tree = ttk.Treeview(
            tree_frame,
            style="Preview.Treeview",
            xscrollcommand=h_scrollbar.set,
            yscrollcommand=v_scrollbar.set
        )
        self.tree.pack(fill=BOTH, expand=True)
 
        # 配置滾動條
        h_scrollbar.config(command=self.tree.xview)
        v_scrollbar.config(command=self.tree.yview)
 
        # 創(chuàng)建統(tǒng)計信息面板
        stats_frame = ttk.Frame(preview_frame)
        stats_frame.pack(fill=X, pady=(10, 0))
 
        self.stats_label = ttk.Label(stats_frame, text="", style="Title.TLabel")
        self.stats_label.pack(side=LEFT)
 
    def create_status_bar(self):
        self.status_var = StringVar()
        self.status_bar = ttk.Label(
            self.window,
            textvariable=self.status_var,
            relief=SUNKEN,
            padding=(5, 2)
        )
        self.status_bar.pack(fill=X, padx=5, pady=2)
 
    def toggle_status_bar(self):
        # 切換狀態(tài)欄顯示/隱藏
        if self.status_bar.winfo_viewable():
            self.status_bar.pack_forget()
        else:
            self.status_bar.pack(fill=X, padx=5, pady=2)
 
    def update_preview(self):
        # 清空現(xiàn)有數(shù)據(jù)
        for item in self.tree.get_children():
            self.tree.delete(item)
 
        if self.data_handler.df is not None:
            df = self.data_handler.df
            # 設置列
            self.tree["columns"] = list(df.columns)
            self.tree["show"] = "headings"
 
            for column in df.columns:
                self.tree.heading(column, text=column)
                self.tree.column(column, width=100, anchor='center')
 
            # 添加數(shù)據(jù)(僅顯示前100行)
            for i, row in df.head(100).iterrows():
                self.tree.insert("", END, values=list(row))
 
            # 更新統(tǒng)計標簽
            stats = self.data_handler.get_statistics()
            self.stats_label.config(
                text=f"行數(shù): {stats['row_count']} | 列數(shù): {stats['column_count']}"
            )
 
            # 更新狀態(tài)欄
            self.status_var.set(
                f"當前加載文件: {os.path.basename(self.file_path.get())} | "
                f"行數(shù): {stats['row_count']} | 列數(shù): {stats['column_count']}"
            )
        else:
            self.status_var.set("請先加載文件")
 
    def show_help(self):
        help_text = """
Excel數(shù)據(jù)格式化批處理工具使用說明:
 
1. 文件操作:
   - 點擊"瀏覽"選擇Excel文件
   - 點擊"保存"保存處理后的文件
 
2. 數(shù)據(jù)清洗功能:
   - 刪除重復行:刪除完全重復的數(shù)據(jù)行
   - 刪除空行:刪除全為空值的行
   - 去除空格:刪除文本中的首尾空格
   - 統(tǒng)一大小寫:統(tǒng)一文本的大小寫格式
   - 數(shù)值格式化:統(tǒng)一數(shù)值的小數(shù)位數(shù)
   - 日期格式化:統(tǒng)一日期的顯示格式
   - 刪除特殊字符:清除文本中的特殊字符
   - 填充空值:使用多種方式填充缺失值
 
3. 數(shù)據(jù)分析:
   - 查看基本統(tǒng)計信息
   - 空值分析
   - 數(shù)據(jù)分布可視化
 
4. 快捷鍵:
   - Ctrl+O:打開文件
   - Ctrl+S:保存文件
   - Ctrl+Z:撤銷
   - Ctrl+Y:重做
   - F1:顯示幫助
        """
 
        help_window = Toplevel(self.window)
        help_window.title("使用說明")
        help_window.geometry("600x400")
 
        help_text_widget = ScrolledText(help_window, wrap=WORD, width=70, height=20)
        help_text_widget.pack(padx=10, pady=10, fill=BOTH, expand=True)
        help_text_widget.insert(END, help_text)
        help_text_widget.configure(state='disabled')
 
    def show_about(self):
        about_text = """
Excel數(shù)據(jù)格式化批處理工具
 
功能特點:
- 支持多種數(shù)據(jù)清洗操作
- 實時預覽數(shù)據(jù)變化
- 數(shù)據(jù)分析和可視化
- 后臺處理,避免卡頓
- 撤銷/重做功能
- 友好的圖形界面
 

        """
 
        messagebox.showinfo("關于", about_text)
 
if __name__ == "__main__":
    try:
        app = ExcelCleaner()
        app.run()
    except Exception as e:
        logging.error(f"程序運行錯誤: {str(e)}")
        messagebox.showerror("錯誤", f"程序運行出錯:{str(e)}")
         
# 優(yōu)化的代碼,運行即出現(xiàn)GUI界面

9.總結

Excel格式化批處理工具是數(shù)據(jù)分析和日常辦公中不可或缺的步驟。本工具提供了一系列高效的功能,幫助用戶快速整理數(shù)據(jù),提升數(shù)據(jù)質量。無論是數(shù)據(jù)分析師還是日常辦公人員,都可以借助該工具提高工作效率,減少數(shù)據(jù)整理的繁瑣工作。希望本篇指南能幫助大家更好地利用工具,提高數(shù)據(jù)處理能力!

以上就是使用Python實現(xiàn)Exce格式化批處理工具的詳細內容,更多關于Python Exce格式化的資料請關注腳本之家其它相關文章!

相關文章

  • Python的高級Git庫 Gittle

    Python的高級Git庫 Gittle

    Gittle是一個高級純python git 庫。構建在dulwich之上,提供了大部分的低層機制
    2014-09-09
  • pip中global.cache-dir的具體使用

    pip中global.cache-dir的具體使用

    global.cache-dir是pip的全局緩存目錄,它的主要作用是存儲下載的包文件和構建過程中生成的緩存,本文就來介紹一下global.cache-dir的具體使用
    2025-08-08
  • Python使用SymPy和Manim輕松搞定導數(shù)動畫

    Python使用SymPy和Manim輕松搞定導數(shù)動畫

    大家好,你有沒有試過在 Manim 里做導數(shù)定義的動畫,這篇文章小編就來和大家詳細介紹一下Python如何使用SymPy和Manim輕松搞定導數(shù)動畫吧
    2026-05-05
  • Python學習之sys模塊使用教程詳解

    Python學習之sys模塊使用教程詳解

    sys模塊?與?os包一樣,也是對系統(tǒng)資源進行調用。功能同樣也是非常豐富。本文將對sys模塊的一些簡單且常用的函數(shù)進行介紹,感興趣的可以學習一下
    2022-03-03
  • Python+OpenCV實現(xiàn)分水嶺分割算法的示例代碼

    Python+OpenCV實現(xiàn)分水嶺分割算法的示例代碼

    分水嶺算法是用于分割的經(jīng)典算法,在提取圖像中粘連或重疊的對象時特別有用。本文將用Python+OpenCV實現(xiàn)這一算法,需要的可以參考一下
    2022-08-08
  • 關于tensorflow和keras版本的對應關系

    關于tensorflow和keras版本的對應關系

    這篇文章主要介紹了關于tensorflow和keras版本的對應關系,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • PyTorch?Autograd的核心原理和功能深入探究

    PyTorch?Autograd的核心原理和功能深入探究

    本文深入探討了PyTorch中Autograd的核心原理和功能,從基本概念、Tensor與Autograd的交互,到計算圖的構建和管理,再到反向傳播和梯度計算的細節(jié),最后涵蓋了Autograd的高級特性
    2024-01-01
  • python技能之數(shù)據(jù)導出excel的實例代碼

    python技能之數(shù)據(jù)導出excel的實例代碼

    本篇文章主要介紹了python技能之導出excel的實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • Python最長公共子串算法實例

    Python最長公共子串算法實例

    這篇文章主要介紹了Python最長公共子串算法,實例分析了Python字符串操作的技巧,需要的朋友可以參考下
    2015-03-03
  • python的函數(shù)最詳解

    python的函數(shù)最詳解

    這篇文章主要介紹了詳解python中各種的函數(shù),是Python入門中的基礎知識,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-10-10

最新評論

穆棱市| 温宿县| 舒城县| 通河县| 伊宁市| 虹口区| 兴安盟| 英吉沙县| 桐乡市| 全州县| 万载县| 方正县| 若尔盖县| 邢台县| 东山县| 安顺市| 太和县| 莒南县| 凤庆县| 富顺县| 浦北县| 上思县| 锦屏县| 边坝县| 保山市| 南丹县| 健康| 贵南县| 建德市| 金塔县| 太仆寺旗| 城步| 息烽县| 桃园县| 古蔺县| 邢台市| 讷河市| 伽师县| 灌南县| 琼结县| 长丰县|