Python批次分割Excel後逐行做差、合併檔案的方法

疯狂学习GIS發表於2024-09-03

  本文介紹基於Python語言,針對一個資料夾下大量的Excel表格檔案,基於其中每一個檔案,首先依據某一列資料的特徵擷取我們需要的資料,隨後對擷取出來的資料逐行求差,並基於其他多個資料夾中同樣大量的Excel表格檔案,進行資料跨檔案合併的具體方法。

  首先,我們來明確一下本文的具體需求。現有一個資料夾,其中有大量的Excel表格檔案(在本文中我們就以.csv格式的檔案為例),且每一個檔案名稱都表示該檔案對應的資料來源點的ID;如下圖所示。

image

  其中,每一個Excel表格檔案都有著如下圖所示的資料格式;其中的第1列,是表示天數的時間資料,每一行資料之間的時間跨度是8天。

  我們希望實現的是,首先對於這個資料夾中的每一個檔案,都擷取出其中天數在2022001(也就是2022年第1天)及之後的部分;隨後,對擷取出來的資料的各列(除了第1列,因為第1列是表示時間的資料)加以逐行求差——例如,用2022009的資料減去2022001的資料,隨後用2022017的資料減去2022009的資料,並將差值作為新的幾列放在原有的幾列後面;還有,我們還希望從當前檔案的檔名、以及第1列的天數中,提取出一些關鍵資訊,作為新的列放在後面(我這裡是希望生產一個深度神經網路迴歸的訓練資料,所以就需要組合各類的資料)。此外,我們還有2個資料夾,其中有著同樣大量、同樣檔案命名規則、同樣資料格式的資料,我們希望將這2個資料夾中與當前資料夾中每一個同名的檔案中的同一天的資料合併。

  瞭解了需求,我們就可以開始程式碼的書寫。本文用到的程式碼如下所示。

# -*- coding: utf-8 -*-
"""
Created on Thu May 18 11:36:41 2023

@author: fkxxgis
"""

import os
import numpy as np
import pandas as pd

original_path = "E:/01_Reflectivity/99_Model_Training/00_Data/02_Extract_Data/17_HANTS"
era5_path = "E:/01_Reflectivity/99_Model_Training/00_Data/03_Meteorological_Data/02_AllERA5"
history_path = "E:/01_Reflectivity/99_Model_Training/00_Data/02_Extract_Data/18_AllYearAverage_2"
output_path = "E:/01_Reflectivity/99_Model_Training/00_Data/02_Extract_Data/19_2022Data"

era5_files = os.listdir(era5_path)
history_files = os.listdir(history_path)

for file in os.listdir(original_path):
    file_path = os.path.join(original_path, file)
    
    if file.endswith(".csv") and os.path.isfile(file_path):
        point_id = file[4 : -4]
        
        df = pd.read_csv(file_path)
        filter_df = df[df["DOY"] >= 2022001]
        filter_df = filter_df.reset_index(drop = True)
        filter_df["blue_dif"] = filter_df["blue"].diff()
        filter_df["green_dif"] = filter_df["green"].diff()
        filter_df["red_dif"] = filter_df["red"].diff()
        filter_df["inf_dif"] = filter_df["inf"].diff()
        filter_df["si1_dif"] = filter_df["si1"].diff()
        filter_df["si2_dif"] = filter_df["si2"].diff()
        filter_df["NDVI_dif"] = filter_df["NDVI"].diff()
        filter_df["PointType"] = file[4 : 7]
        filter_df["days"] = filter_df["DOY"] % 1000
        
        for era5_file in era5_files:
            if point_id in era5_file:
                era5_df = pd.read_csv(os.path.join(era5_path, era5_file))
                
                rows_num = filter_df.shape[0]
                for i in range(rows_num):
                    day = filter_df.iloc[i, 0]
                    row_need_index = era5_df.index[era5_df.iloc[ : , 1] == day]
                    row_need = row_need_index[0]
                    sola_data_all = era5_df.iloc[row_need - 2 : row_need, 2]
                    temp_data_all = era5_df.iloc[row_need - 6 : row_need - 2, 3]
                    prec_data_all = era5_df.iloc[row_need - 5 : row_need - 1, 4]
                    soil_data_all = era5_df.iloc[row_need - 6 : row_need - 2, 5 : 7 + 1]
                    sola_data = np.sum(sola_data_all.values)
                    temp_data = np.sum(temp_data_all.values)
                    prec_data = np.sum(prec_data_all.values)
                    soil_data = np.sum(soil_data_all.values)
                    filter_df.loc[i, "sola"] = sola_data
                    filter_df.loc[i, "temp"] = temp_data
                    filter_df.loc[i, "prec"] = prec_data
                    filter_df.loc[i, "soil"] = soil_data
                break
            
        for history_file in history_files:
            if point_id in history_file:
                history_df = pd.read_csv(os.path.join(history_path, history_file)).iloc[ : , 1 : ]
                history_df.columns = ["blue_h", "green_h", "red_h", "inf_h", "si1_h", "si2_h", "ndvi_h"]
                break
        
        filter_df_new = pd.concat([filter_df, history_df], axis = 1)
                
        output_file = os.path.join(output_path, file)
        filter_df_new.to_csv(output_file, index = False)

  程式碼中首先定義了幾個資料夾路徑,分別是原始資料資料夾(也就是本文開頭第1張圖所示的資料夾)、ERA5氣象資料資料夾、歷史資料資料夾和輸出資料夾。然後,透過 os.listdir() 函式獲取了ERA5氣象資料資料夾和歷史資料資料夾中的所有檔名,並在後續的迴圈中使用。

  接下來是一個 for 迴圈,遍歷了原始資料資料夾中的所有.csv檔案,如果檔名以 .csv 結尾並且是一個合法的檔案,則讀取該檔案。然後,根據檔名提取了點ID,並使用Pandas中的 read_csv() 函式讀取了該檔案的資料。接著,使用Pandas中的 loc[] 函式對資料進行了處理,包括篩選出DOY大於等於 2022001 的行,將其重置索引,並計算了反射率資料的差值。然後,將一些後設資料新增到篩選後的資料中,包括點型別和天數。

  接下來是兩個 for 迴圈,分別用於處理ERA5氣象資料和歷史資料。在處理ERA5氣象資料時,首先找到與當前點ID匹配的ERA5氣象資料檔案,並使用Pandas中的 read_csv() 函式讀取了該檔案的資料。然後,使用 iloc[] 函式根據當前日期找到了ERA5氣象資料中對應的行,並從該行及其前兩行中提取了太陽輻射、溫度、降水和土壤溼度資料。最後,將這些資料新增到篩選後的資料中。

  在處理歷史資料時,首先找到與當前點ID匹配的歷史資料檔案,並使用Pandas中的 read_csv() 函式讀取了該檔案的資料。然後,使用 iloc[] 函式刪除了第一列,並將剩餘列重新命名為blue_hgreen_hred_hinf_hsi1_hsi2_hndvi_h。最後,使用Pandas中的 concat() 函式將篩選後的資料和歷史資料合併成一個新的DataFrame

  最後,使用Pandas中的 to_csv() 函式將新的DataFrame儲存到輸出資料夾中。

  執行上述程式碼,我們即可得到無數個組合後的Excel表格檔案,其中每一個檔案的列都如下圖所示,已經是我們合併了各類資訊之後的了。

  這樣,就完成了我們神經網路訓練資料集的生產過程。

  至此,大功告成。

相關文章