天天看點

企業資料清洗項目實踐day4

代碼在上次的基礎上做了一點優化,之前對項目要的最終結果了解有些偏差:

原始資料的那一列行業編碼是存在三位數和四位數的,我上次了解的三位數就是分割成兩位數進行查找,其實三位數的編碼是由于第一位的0沒有顯示,

是以例如311的編碼其實應該是0311,是以代碼進行了修改,對于三位數需要在開頭的位置補一個0,成為四位數再進行查找。

把三個方法的參數做了優化,擷取json字元串的方法隻需要一個參數(國标檔案),擷取單個結果的方法需要兩個參數(待查字元串,國标檔案),

擷取整個檔案需要三個參數(原始資料檔案,建立檔案,國标檔案)這個方法原始資料檔案每一行的編碼的周遊+使用國标檔案調用擷取json的方法一個個獲得結果。

最終結果圖:

企業資料清洗項目實踐day4

源代碼:

1 import pandas as pd
  2 import xlwt
  3 
  4 """
  5 rank的一系列變量是生成json字元串需要的标志
  6 由于json結構是循環周遊生成的,是以在每一層都要留下标記,以便于下一層的建構
  7 """
  8 
  9 rank10=""    #A  門類編号
 10 rank11=""    #A  門類名字
 11 rank20=""    #01 大類編号
 12 rank21=""    #   大類名字
 13 rank30=""    #012 中類編号
 14 rank31=""    #    中類名字
 15 rank40=""    #0121小類編号
 16 rank41=""    #    小類名字
 17 
 18 """
 19 ------------------------------------------------------------------------------------------------------------------------
 20 """
 21 
 22 def get_json(stdfilepwd):
 23     """
 24     :param stdfilepwd:标準國标檔案
 25     :return: 标準行業次元json
 26     """
 27     """
 28     filepwd 國标檔案格式
 29     A    農、林、牧、漁業
 30     A    農、林、牧、漁業
 31     01    農業
 32     011    谷物種植
 33     0111    稻谷種植
 34     0112    小麥種植
 35     0113    玉米種植
 36     """
 37     # dict={"A":{"01":{"011":"谷物種植","0111":"稻谷種植"} ,
 38     #            "02":{"021":"林木育種和育苗","0211":"林木育種"}},
 39     #
 40     #       "B":{"06":{ "0610":"煙煤和無煙煤開采洗選","0620":"褐煤開采洗選"},
 41     #            "07":{"0710":"石油開采","0720":"天然氣開采"}}
 42     #       }
 43     # layer1=dict['A']
 44     # print("第一層 A:\n",layer1)
 45     #
 46     # layer2 = dict['A']['01']
 47     # print("第二層 01農業:\n", layer2)
 48     #
 49     # layer3 = dict['A']['01']["011"]
 50     # print("第三層 :\n", layer3)
 51     #讀取标準檔案 df預設不讀取第一行資料
 52     df = pd.read_excel(stdfilepwd)
 53     #首先尋找第一層大寫字母層的資料 定位行loc[] 定位
 54     # print(df.columns.values[0]) #A
 55 
 56     my_dict={"A":{}}                #最終生成的字典
 57     new_dict={"A":
 58                   {"農、林、牧、漁業":
 59                        {"01":
 60                             {"農業":
 61                                  {"001":
 62                                       {"谷物種植":
 63                                           {
 64                                             "0111":"稻谷種植","0112":"小麥種植"
 65                                           }
 66                                        }
 67                                   }
 68                              }
 69                         }
 70                    }
 71               }
 72     # new_dict["A"].update(
 73     #     {df.loc[0].values[0]:df.loc[0].values[1]}
 74     # )
 75     # print("excel表的行數:\n",len(df.index.values))
 76     # print("測試字典:\n",new_dict)
 77     # print(df.loc[80].values)
 78     # print("一個單元格資料的資料類型:\n",type(df.loc[0].values[0]))
 79 
 80     #測試完畢 開始建構行業領域分類字典
 81     #開始周遊表格 0 - 1423
 82     for i in range(len(df.index.values)):
 83         #由于表格的第一列資料的數字被判定為int型 是以要轉化成str
 84         temp=df.loc[i].values
 85         #轉化字元串 為了保險起見 兩列統一化處理 均轉化為字元串
 86         # one 就是編碼 two就是編碼對應的行業名稱
 87         one = str(temp[0])
 88         # print(len(one))
 89         two = str(temp[1])
 90         # print("資料格式:\n",type(temp[0]))
 91         #通過判斷values[0](數字編碼)的字元串的長度判斷處于字典的哪一層 如果長度是1 那麼在第一層門類 如果長度是2那麼在第二層大類 如果長度是3那麼在第三層中類
 92         if(len(one)==1):
 93             #rank10儲存編碼 rank11儲存行業名稱 後面類似
 94             global rank10
 95             global rank11
 96             rank10=one
 97             rank11=two
 98             my_dict.update({rank10:{rank11:{}}})
 99         if(len(one)==2):
100             global rank20
101             global rank21
102             rank20 = one
103             rank21 = two
104             my_dict[rank10][rank11].update({rank20:{rank21:{}}})
105         if (len(one) == 3):
106             global rank30
107             global rank31
108             rank30 = one
109             rank31 = two
110             #雖然會出現21 , 2111 中間沒有210的情況出現 但是可以優先生成所有的中類三位數的json結構 這一層會保留最後一個三位數中類 可以在後面進行判斷
111             my_dict[rank10][rank11][rank20][rank21].update({rank30:{rank31:{}}})
112             #這裡做了代碼的前三位字元串切分,為了判斷一下有沒有小類跳過中類的情況,需要直接跨過中類存儲,少了一層字典{}
113         if (len(one) == 4):
114             global rank40
115             global rank41
116             rank40 = one
117             rank41 = two
118             #把編碼分片 隻取前三位 然後和距離這個編碼最近的那個三位數中類做比較 如果相同則可以放到該中類的下一層字典 如果不同則該四位編碼自成一個字典
119             divide_rank40=rank40[:3]
120             # print(divide_rank40,rank30)
121             #判等
122             if(divide_rank40==rank30):
123                 # print("!!!!!~~~~~~~~~~~~")
124                 #相等 -> 放入該中類的下一層字典
125                 my_dict[rank10][rank11][rank20][rank21][rank30][rank31].update({rank40:rank41})
126             else:
127                 #不等 -> 自己成為一個字典 在大類裡直接自成一個字典
128                 my_dict[rank10][rank11][rank20][rank21].update({rank40: rank41})
129     #得到最終的字典my_dict
130     # print(my_dict.keys())
131     # print(my_dict)
132     return my_dict
133 """
134 最終生成的json檔案
135 
136 'A': {
137         '農、林、牧、漁業': {
138             '01': {
139                 '農業': {
140                     '011': {
141                         '谷物種植': {
142                             '0111': '稻谷種植',
143                             '0112': '小麥種植',
144                             '0113': '玉米種植',
145                             '0119': '其他谷物種植'
146                         }
147                     },
148                     '012': {
149                         '豆類、油料和薯類種植': {
150                             '0121': '豆類種植',
151                             '0122': '油料種植',
152                             '0123': '薯類種植'
153                         }
154                     },
155                     '013': {
156                         '棉、麻、糖、煙草種植': {
157                             '0131': '棉花種植',
158                             '0132': '麻類種植',
159                             '0133': '糖料種植',
160                             '0134': '煙草種植'
161                         }
162                     },
163                     '014': {
164                     
165 """
166 
167 
168 """
169 ------------------------------------------------------------------------------------------------------------------------
170 """
171 
172 def ger_stdstr(qb03,stdfilepwd):
173     """
174     :param qb03,stdfilepwd:
175     :return: str 标準行業次元字元串 行業代碼·門類名稱·大類名稱·中類名稱·小類名稱
176     qb03,待查編碼
177     stdfilepwd,标準國标檔案
178     """
179     #設定個标記,初始值False 說明預設找不到這個編碼 如果找到了則設為True 如果最終是False則重新分割字元串,回調函數
180     flag = False
181     #擷取字典
182     my_dict={}
183     my_dict.update(get_json(stdfilepwd))
184     # print(my_dict)
185 
186     category=""     #門類 名字
187 
188     big_class=""    #大類 名字
189 
190     medium_class="" #中類 名字
191 
192     small_class=""  #小類 名字
193     # for 周遊第一層 門類
194     for items in my_dict.items():
195         res = ""                       #    定義該方法最終要傳回的标準化行業次元字元串
196         # print(items[0])                 #ABCD
197         for layer_0 in items[1].items():                #這個for循環已經進入了 第一層 {} 裡面格式是 (門類名稱:{ })
198             # print("門類:\n",layer_0)
199             # print("門類名稱:\n",layer_0[0])
200             category=layer_0[0]                         #門類名稱[0]
201             """
202             -------------------------------------------------------------------
203             """
204             # 周遊第二層大類
205             """
206             每進入一層周遊,第一個for循環是進入一個這樣格式的資料 ( 編碼:{  } ) [0]是名稱 [1]是字典
207             之後第二個for循環進入那個字典{ }
208             字典建構的方式是 上一層是key 下一層是對應的value 同時它作為下一層的key
209             """
210             for layer_10 in layer_0[1].items():
211                 # print("大類編碼(兩位):\n",layer_10[0])
212                 #進入A對應的{ }
213                 for layer_11 in layer_10[1].items():        #這個for循環已經進入了 第二層 {} 裡面格式是 (大類名稱:{ })
214                     # print("大類:\n",layer_11)
215                     big_class = layer_11[0]
216                     # print("大類名稱:\n",big_class)
217                     """
218                     ---------------------------------------
219                     """
220                     #進入大類(01,{ })
221                     for layer_20 in layer_11[1].items():#這個for循環已經進入了 第三層 {} 裡面格式是 (中類名稱:{ })或者不正常的跨過中類的四位編碼
222                         # 這個分支的意思是有的類别隻到了大類,沒有經過中類直接分到了四位數的小類,是以必須分開周遊
223                         #判斷第二層下一級的編碼是三位還是四位,如果是三位那麼是正常的中類劃分,如果是四位,那麼是跳過了中類劃分到了小類
224                         if(len(layer_20[0])==4):
225                             small_class=layer_20[1]
226                             # print("大類直接分到小類:\n",small_class)
227                             #判斷字元串
228                             if(qb03==layer_20[0]):
229                                 print("跨過中類的小類,判斷成功!",qb03)
230                                 flag=True
231                                 res = items[0]+ qb03+ "·"+ category + "·" + big_class + "·"+small_class
232                                 return res
233                         else:
234                             for layer_21 in layer_20[1].items():    #這個for循環已經進入了 第三層正常的中類 {} 裡面格式是 (中類名稱:{ })
235                                 # print("中類:\n",layer_21)
236                                 medium_class = layer_21[0]
237                                 # print("中類名稱:\n",medium_class)
238                                 # 這裡是個大坑,我的周遊是進入值的那一層,編碼在上一級的周遊 layer_20[0]
239                                 # if (qb03 == layer_20[0]):
240                                 #     print("三位中類判斷成功!", qb03)
241                                 #     flag=True
242                                 #     res = qb03 + "·" + category + "·" + big_class + "·" + medium_class
243                                 #     return res
244                                 #繼續劃分到小類
245                                 for layer_30 in layer_21[1].items():    #這個for循環已經進入了 第四層 {} 裡面格式是 (小類名稱:{ })
246                                     #這個layer_30就是最後一層的四位數資料了 格式: ('0111', '稻谷種植') 是一個tuple 索引0是編碼1是名稱
247                                     small_class=layer_30[1]
248                                     # print("小類名稱:\n",small_class)
249                                     #--------------------------------------------------------------------------------
250                                     # 判斷字元串
251                                     if (qb03 == layer_30[0]):
252                                         print("正常四位小類判斷成功!", qb03)
253                                         flag=True
254                                         res=items[0]+qb03+"·"+category+"·"+big_class+"·"+medium_class+"·"+small_class
255                                         return res
256     #這裡是對沒有找到的編碼進行二次尋找,字元串拼接,最前面加個0
257     if(flag==False):
258         new_qb03="0"+qb03
259         return ger_stdstr(new_qb03,stdfilepwd)               #遞歸調用自身
260 
261 """
262 ------------------------------------------------------------------------------------------------------------------------
263 """
264 
265 def do_clean(filepwd,newfilepwd,stdfilepwd):
266     """
267     1、讀取源資料表格
268     2、逐個把資料傳入get_stdstr(qb03,stdfilepwd)方法獲得傳回值存回excel表格
269     參數:需要清洗的行業編碼,單列資料
270     filepwd,需要清洗的檔案
271     newfilepwd,新生成的檔案存儲路徑
272     stdfilepwd,标準的國标檔案
273     :return:None
274     """
275     """
276     待清洗的檔案格式:filepwd
277     QB03
278     2812
279     3511
280     3071
281     3434
282     2614
283     3620
284     2613
285     2614
286     3512
287     
288     清洗完畢的檔案格式:newfilepwd
289     data
290     2812·制造業·化學纖維制造業·纖維素纖維原料及纖維制造·人造纖維(纖維素纖維)制造
291     3511·制造業·專用裝置制造業·采礦、冶金、建築專用裝置制造·礦山機械制造
292     3071·制造業·非金屬礦物制品業·陶瓷制品制造·衛生陶瓷制品制造
293     3434·制造業·通用裝置制造業·物料搬運裝置制造·連續搬運裝置制造
294     2614·制造業·化學原料和化學制品制造業·基礎化學原料制造·有機化學原料制造
295     3620·制造業·汽車制造業·改裝汽車制造·改裝汽車制造
296     2613·制造業·化學原料和化學制品制造業·基礎化學原料制造·無機鹽制造
297     2614·制造業·化學原料和化學制品制造業·基礎化學原料制造·有機化學原料制造
298     3512·制造業·專用裝置制造業·采礦、冶金、建築專用裝置制造·石油鑽采專用裝置制造
299     3599·制造業·專用裝置制造業·環保、社會公共服務及其他專用裝置制造·其他專用裝置制造
300     511·批發和零售業·批發業·農、林、牧産品批發·農、林、牧産品批發
301     3821·制造業·電氣機械和器材制造業·輸配電及控制裝置制造·變壓器、整流器和電感器制造
302     6520·資訊傳輸、軟體和資訊技術服務業·軟體和資訊技術服務業·資訊系統內建服務·資訊系統內建服務
303     7330·科學研究和技術服務業·研究和試驗發展·農業科學研究和試驗發展·農業科學研究和試驗發展
304     2922·制造業·橡膠和塑膠制品業·塑膠制品業·塑膠闆、管、型材制造
305     """
306     df=pd.read_excel(filepwd)
307     # print(df.loc[0].values)
308     res=[]
309     temp_res=""
310     #range(len(df.index.values))
311     for i in range(len(df.index.values)):
312         # print(df.loc[i].values[0])
313         """
314         ger_stdstr()
315         兩個參數 一個是待查編碼   一個是标準json檔案路徑
316         """
317         temp_res=ger_stdstr(str(df.loc[i].values[0]),stdfilepwd)
318         print(temp_res)
319         if(temp_res!=None):
320             res.append(temp_res)
321         else:
322             res.append(str(df.loc[i].values[0]))
323     # print(res)
324     #把結果存儲到excel表
325     workbook = xlwt.Workbook(encoding='utf-8')
326     sheet = workbook.add_sheet('sheet1', cell_overwrite_ok=True)
327     sheet.col(0).width=256*100
328     sheet.write(0, 0, "DATA")
329     for i in range(len(res)):
330         sheet.write(i+1, 0, res[i])
331     workbook.save(newfilepwd)
332     return None
333 if __name__ == '__main__':
334     #封裝方法getjson()
335     """
336     1、封裝建構json的方法 getjson() , 方法有一個參數 參數是檔案路徑
337     檔案的格式是兩列,由于讀取檔案不包括表頭,如果表頭資料有需要的話 需要複制一行表頭資料
338     第一列是行業編碼 第二列是行業名稱
339     """
340     #測試調用
341     stdfilepwd="GBT4754-2011.xlsx"
342     # get_json(stdfilepwd)
343     """
344     --------------------------------------------------------------
345     """
346 
347     #封裝方法do_clean(filepwd,newfilepwd,stdfilepwd)
348     # 測試調用
349     filepwd="2013_year_data.xlsx" #需要處理的檔案路徑13年
350     newfilepwd="2013_res_data.xls"  #處理完畢轉存的檔案路徑13年
351 
352     filepwd16 = "2016_year_data.xlsx"  # 需要處理的檔案路徑16年
353     newfilepwd16 = "2016_res_data.xls"  # 處理完畢轉存的檔案路徑16年
354     do_clean(filepwd16, newfilepwd16, stdfilepwd)
355 
356     """
357     --------------------------------------------------------------
358     """
359     #封裝ger_stdstr(qb03,jsonfilepwd) 方法   參數1是四位待查編碼  參數2是json檔案的路徑
360     # res=ger_stdstr("321",stdfilepwd)
361     # print(res)