Pandas之旅(五): 構建模型初入門:檢驗資料一致性
Pandas 如何根據需要建立簡單模型
大家好,今天這一期我想和大家分享有關於pandas建立模型的部分,首先讓我們來看一個比較常見的場景:
你每天需要開啟N個excel進行相同的操作,各種眼花繚亂的VBA函式後老眼昏花。。。。
這種情況下,最好的解決辦法是先仔細想想業務需求是什麼,根據實際情況可以用pandas搭建一個小型模型,一旦搭建完畢,你每天上班時就可以愉快地執行Python指令碼,轉身去喝杯咖啡,幾分鐘後心滿意足地回來,發現所有的繁瑣操作已經搞定了,生活是這麼美好、、、
閒話少說,讓我今天拋磚引玉,為大家簡單介紹一個我使用比較多的小模型:檢驗資料一致性(新老資料增加和減少的數量一致),今天的文章主要分為5部分
- 製作假資料
- 明確模型目的
- 開始實踐
- 原始碼及GitHub地址
好啦,話不多說,讓我們一個個看吧
1. 製作假資料
import os
#這兩行僅僅是切換路徑,方便我上傳Github,大家不用理會 os.chdir("F:\\Python教程\\segmentfault\\pandas_share\\Pandas之旅_05 如何構建基礎模型") os.getcwd()
'F:\\Python教程\\segmentfault\\pandas_share\\Pandas之旅_05 如何構建基礎模型'
首先讓我們一起製作一些假資料,我這裡接下來生成一些有關訂單的假資料,當然,到了文章的最後可能你會發現我們的模型並不是完美適用於這個型別,你會在生活中根據自己需要來調整,但是至少基礎的思路已經有啦!
先建立一個fake_product的字典,keys是產品,value是單價,這裡我們用一個在網上隨便找到的商品名稱的csv資料集,它只有一列ProductNames,product_names.csv和最後的程式碼都會放在github上,如果大家感興趣可以下載~
import numpy as np import pandas as pd f"Using {pd.__name__},{pd.__version__}"
'Using pandas,0.23.0'
fake_df = pd.read_csv("product_names.csv") fake_df.head(10)
Product_Names | |
---|---|
0 | TrailChef Deluxe Cook Set |
1 | TrailChef Double Flame |
2 | Star Dome |
3 | Star Gazer 2 |
4 | Hibernator Lite |
5 | Hibernator Extreme |
6 | Hibernator Camp Cot |
7 | Firefly Lite |
8 | Firefly Extreme |
9 | EverGlow Single |
fake_df['Product_Names'].is_unique
True
這裡我們可以看到,資料集主要包括的就是一些產品的名字,而且沒有重複值,我們現在把他們匯出至一個字典,並隨機給每個產品任意的價格(在20至100之間),因為這裡我們要隨機生成一些假資料,所以讓我們引用random這個包
import random
fake_product = { k:random.randint(20,100) for k in fake_df['Product_Names']} fake_product
{'TrailChef Deluxe Cook Set': 62, 'TrailChef Double Flame': 78, 'Star Dome': 58, 'Star Gazer 2': 73, 'Hibernator Lite': 56, 'Hibernator Extreme': 99, 'Hibernator Camp Cot': 33, 'Firefly Lite': 27, 'Firefly Extreme': 30, 'EverGlow Single': 44, 'EverGlow Butane': 33, 'Husky Rope 50': 59, 'Husky Rope 60': 81, 'Husky Rope 100': 71, 'Husky Rope 200': 81, 'Granite Climbing Helmet': 86, 'Husky Harness': 76, 'Husky Harness Extreme': 73, 'Granite Signal Mirror': 67, 'Granite Carabiner': 63, 'Granite Belay': 49, 'Granite Pulley': 48, 'Firefly Climbing Lamp': 47, 'Firefly Charger': 60, 'Firefly Rechargeable Battery': 52, 'Granite Chalk Bag': 22, 'Granite Ice': 71, 'Granite Hammer': 50, 'Granite Shovel': 41, 'Granite Grip': 74, 'Granite Axe': 68, 'Granite Extreme': 74, 'Mountain Man Extreme': 87, 'Polar Sun': 82, 'Polar Ice': 47, 'Edge Extreme': 53, 'Bear Survival Edge': 81, 'Glacier GPS Extreme': 48, 'BugShield Extreme': 87, 'Sun Shelter Stick': 42, 'Compact Relief Kit': 46, 'Aloe Relief': 24, 'Infinity': 73, 'TX': 43, 'Legend': 100, 'Kodiak': 44, 'Capri': 31, 'Cat Eye': 62, 'Dante': 71, 'Fairway': 77, 'Inferno': 59, 'Maximus': 38, 'Trendi': 35, 'Zone': 87, 'Max Gizmo': 67, 'Pocket Gizmo': 73, 'Ranger Vision': 73, 'Trail Master': 96, 'Hailstorm Steel Irons': 79, 'Hailstorm Titanium Irons': 31, 'Lady Hailstorm Steel Irons': 91, 'Lady Hailstorm Titanium Irons': 99, 'Hailstorm Titanium Woods Set': 74, 'Hailstorm Steel Woods Set': 30, 'Lady Hailstorm Titanium Woods Set': 99, 'Lady Hailstorm Steel Woods Set': 84, 'Course Pro Putter': 64, 'Blue Steel Putter': 26, 'Blue Steel Max Putter': 96, 'Course Pro Golf and Tee Set': 90, 'Course Pro Umbrella': 20, 'Course Pro Golf Bag': 66, 'Course Pro Gloves': 61, 'TrailChef Canteen': 60, 'TrailChef Kitchen Kit': 53, 'TrailChef Cup': 88, 'TrailChef Cook Set': 27, 'TrailChef Single Flame': 45, 'TrailChef Kettle': 70, 'TrailChef Utensils': 88, 'Star Gazer 6': 42, 'Star Peg': 28, 'Hibernator': 47, 'Hibernator Self - Inflating Mat': 66, 'Hibernator Pad': 89, 'Hibernator Pillow': 84, 'Canyon Mule Climber Backpack': 82, 'Canyon Mule Weekender Backpack': 92, 'Canyon Mule Journey Backpack': 82, 'Canyon Mule Cooler': 23, 'Canyon Mule Carryall': 56, 'Firefly Mapreader': 77, 'Firefly 2': 76, 'Firefly 4': 75, 'Firefly Multi-light': 91, 'EverGlow Double': 34, 'EverGlow Lamp': 28, 'Mountain Man Analog': 39, 'Mountain Man Digital': 85, 'Mountain Man Deluxe': 84, 'Mountain Man Combination': 40, 'Venue': 56, 'Lux': 44, 'Polar Sports': 20, 'Polar Wave': 62, 'Bella': 45, 'Hawk Eye': 42, 'Seeker 35': 81, 'Seeker 50': 90, 'Opera Vision': 98, 'Glacier Basic': 63, 'Glacier GPS': 66, 'Trail Scout': 32, 'BugShield Spray': 34, 'BugShield Lotion Lite': 90, 'BugShield Lotion': 84, 'Sun Blocker': 88, 'Sun Shelter 15': 45, 'Sun Shelter 30': 100, 'Sun Shield': 62, 'Deluxe Family Relief Kit': 43, 'Calamine Relief': 82, 'Insect Bite Relief': 72, 'Star Lite': 32, 'Star Gazer 3': 95, 'Single Edge': 87, 'Double Edge': 20, 'Bear Edge': 80, 'Glacier Deluxe': 82, 'BugShield Natural': 83, 'TrailChef Water Bag': 99, 'Canyon Mule Extreme Backpack': 58, 'EverGlow Kerosene': 78, 'Sam': 67, 'Polar Extreme': 34, 'Seeker Extreme': 43, 'Seeker Mini': 26, 'Flicker Lantern': 44, 'Trail Star': 47, 'Zodiak': 31, 'Sky Pilot': 58, 'Retro': 99, 'Astro Pilot': 99, 'Auto Pilot': 20}
len(fake_product)
這裡我們看到生成了一個有144個item組成,key為產品名稱,value及單價的fake_product字典,接下來為了省事,
我簡單地建立了一個方法get_fake_data可以讓我們最終得到一個填充好的假資料集合,返回的也是字典
def get_fake_data(id_range_start,id_range_end,random_quantity_range=50): #Id=["A00"+str(i) for i in range(0,id_range)] Id=[] Quantity = [] Product_name=[] Unit_price=[] Total_price=[] for i in range(id_range_start,id_range_end): random_quantity = random.randint(1,random_quantity_range) name, price = random.choice(list(fake_product.items())) Id.append("A00"+str(i)) Quantity.append(random_quantity) Product_name.append(name) Unit_price.append(price) Total_price.append(price*random_quantity) result = { 'Product_ID':Id, 'Product_Name':Product_name, 'Quantity':Quantity, 'Unit_price':Unit_price, 'Total_price':Total_price } return result # total = [quantity[i]* v for i,v in enumerate(unit_price)]也可以最後用推導式來求total,皮一下 # total_price=[q*p for q in quantity for p in unit_price]
首先,這個方法不夠簡潔,大家可以優化一下,但是今天的重點在於小模型,讓我們著重看一下最後返回的dict,它包含如下幾列:
- Product_ID:訂單號,按照順序遞增生成
- Product_Name:產品名稱,隨機生成
- Quantity:隨機生成在1~random_quantity_range之間的每個訂單的產品訂購量
- Unit_price:產品價格
- Total_price:總價
每組資料長度均為 id_range_end - id_range_start,現在讓我們生成兩組假資料:
fake_data= get_fake_data(1,len(fake_product)+1)
這裡我們可以看到我們生成了一組假資料,Id從A001 ~ A00145
讓我們簡單看看假資料的keys和每組資料的長度:
fake_data.keys()
dict_keys(['Product_ID', 'Product_Name', 'Quantity', 'Unit_price', 'Total_price'])
for v in fake_data.values(): print(len(v))
可以發現每組key對應的list長度都是144
2. 明確模型的目的
我們可以利用pandas自帶的from_dict方法把dict轉化為Dataframe,這裡我們分別用剛剛生成的fake_data來模擬1月的庫存和2月的庫存情況,我們可以把fake_data分成兩組,A001-A00140一組,A008-A00144一組,這樣就完美的模擬了實際情況。
因為大多數的商品名稱不會改變(8~140的部分),但是從一月到二月,因為各種原因我們減少了7個商品種類的庫存(1-7),又增加了4個種類的庫存(141-144),我們這裡驗證一致性的公式就是:
新增的 + 一月資料總量 = 減少的 + 二月資料總量
3. 開始實踐
現在讓我們來實現這個小模型,首先生成stock_jan,stock_fev兩個dataframe
stock= pd.DataFrame.from_dict(fake_data) stock.head()
Product_ID | Product_Name | Quantity | Unit_price | Total_price | |
---|---|---|---|---|---|
0 | A001 | Course Pro Golf Bag | 39 | 66 | 2574 |
1 | A002 | EverGlow Kerosene | 18 | 78 | 1404 |
2 | A003 | Lux | 24 | 44 | 1056 |
3 | A004 | Course Pro Putter | 12 | 64 | 768 |
4 | A005 | Seeker 50 | 42 | 90 | 3780 |
stock.set_index(stock['Product_ID'],inplace=True) stock.drop('Product_ID',axis=1,inplace=True) stock.head()
Product_Name | Quantity | Unit_price | Total_price | |
---|---|---|---|---|
Product_ID | ||||
A001 | Course Pro Golf Bag | 39 | 66 | 2574 |
A002 | EverGlow Kerosene | 18 | 78 | 1404 |
A003 | Lux | 24 | 44 | 1056 |
A004 | Course Pro Putter | 12 | 64 | 768 |
A005 | Seeker 50 | 42 | 90 | 3780 |
# 獲得1月份stock資料,A001-A00140 stock_jan=stock[:'A00140'] stock_jan.tail()
Product_Name | Quantity | Unit_price | Total_price | |
---|---|---|---|---|
Product_ID | ||||
A00136 | Flicker Lantern | 1 | 44 | 44 |
A00137 | BugShield Spray | 8 | 34 | 272 |
A00138 | Glacier Basic | 25 | 63 | 1575 |
A00139 | Sun Blocker | 23 | 88 | 2024 |
A00140 | Granite Carabiner | 11 | 63 | 693 |
# 獲得2月份stock資料 stock_fev=stock['A008':] stock_fev.tail()
Product_Name | Quantity | Unit_price | Total_price | |
---|---|---|---|---|
Product_ID | ||||
A00140 | Granite Carabiner | 11 | 63 | 693 |
A00141 | TrailChef Utensils | 24 | 88 | 2112 |
A00142 | TrailChef Deluxe Cook Set | 9 | 62 | 558 |
A00143 | Trail Star | 21 | 47 | 987 |
A00144 | Ranger Vision | 19 | 73 | 1387 |
現在讓我們簡單停頓一下,看看這兩個df:
- stock_jan: A001 - A00140的所有資料
- stock_fev: A008 - A00144的所有資料
接下來的操作很簡單,用我們上篇文章提到的merge函式,這裡merge的公有列為索引Product_ID,Product_Name,使用的是outer merge
merge_keys=['Product_ID','Product_Name']
check_corehence = stock_jan.merge(stock_fev,on=merge_keys,how='outer',suffixes=("_jan","_fev")) check_corehence.head(10)
Product_Name | Quantity_jan | Unit_price_jan | Total_price_jan | Quantity_fev | Unit_price_fev | Total_price_fev | |
---|---|---|---|---|---|---|---|
Product_ID | |||||||
A001 | Course Pro Golf Bag | 39.0 | 66.0 | 2574.0 | NaN | NaN | NaN |
A002 | EverGlow Kerosene | 18.0 | 78.0 | 1404.0 | NaN | NaN | NaN |
A003 | Lux | 24.0 | 44.0 | 1056.0 | NaN | NaN | NaN |
A004 | Course Pro Putter | 12.0 | 64.0 | 768.0 | NaN | NaN | NaN |
A005 | Seeker 50 | 42.0 | 90.0 | 3780.0 | NaN | NaN | NaN |
A006 | Course Pro Golf Bag | 27.0 | 66.0 | 1782.0 | NaN | NaN | NaN |
A007 | Husky Rope 100 | 3.0 | 71.0 | 213.0 | NaN | NaN | NaN |
A008 | EverGlow Double | 18.0 | 34.0 | 612.0 | 18.0 | 34.0 | 612.0 |
A009 | Opera Vision | 30.0 | 98.0 | 2940.0 | 30.0 | 98.0 | 2940.0 |
A0010 | TX | 38.0 | 43.0 | 1634.0 | 38.0 | 43.0 | 1634.0 |
</div>
check_corehence.tail()
Product_Name | Quantity_jan | Unit_price_jan | Total_price_jan | Quantity_fev | Unit_price_fev | Total_price_fev | |
---|---|---|---|---|---|---|---|
Product_ID | |||||||
A00140 | Granite Carabiner | 11.0 | 63.0 | 693.0 | 11.0 | 63.0 | 693.0 |
A00141 | TrailChef Utensils | NaN | NaN | NaN | 24.0 | 88.0 | 2112.0 |
A00142 | TrailChef Deluxe Cook Set | NaN | NaN | NaN | 9.0 | 62.0 | 558.0 |
A00143 | Trail Star | NaN | NaN | NaN | 21.0 | 47.0 | 987.0 |
A00144 | Ranger Vision | NaN | NaN | NaN | 19.0 | 73.0 | 1387.0 |
大家可以發現前7行正是減少的商品庫存,而後4行正是二月份新增的商品庫存,現在讓我們分別獲得減少的商品庫存資料和新增的商品庫存資料:
new_stock = check_corehence.loc[(check_corehence['Quantity_jan'].isnull()) & (check_corehence['Quantity_fev'].notnull())] num_new = new_stock.shape[0] num_new
remove_stock = check_corehence.loc[(check_corehence['Quantity_fev'].isnull()) & (check_corehence['Quantity_jan'].notnull())] num_remove = remove_stock.shape[0] num_remove
再讓我們分別看看1月和2月的資料量:
# 1月資料量 num_stock_jan = stock_jan.shape[0] num_stock_jan
# 2月資料量 num_stock_fev = stock_fev.shape[0] num_stock_fev
現在讓我們套入公式:
num_stock_jan + num_new
num_stock_fev + num_remove
結果相等,資料一致性過關!
4. 原始碼及GitHub地址
這一期為大家分享了一個簡單的pandas檢驗資料一致性的模型,模型還是非常初級階段,功能非常簡單,但是基礎的搭建流程想必大家已經熟悉了,接下來小夥伴們可以根據業務需求搭建自己的模型啦,只要你每天和Excel打交道,總有一款模型適合你
我把這一期的ipynb檔案和py檔案放到了Github上,大家如果想要下載可以點選下面的連結:
- Github倉庫地址:https://github.com/yaozeliang/pandas_share
希望大家能夠繼續支援我,完結,撒花