摘要:生成的隨機數據是亂序的,要按交易日期、分公司、售貨員排序。如果你還不會創建空 DataFrame,關注一下這個知識點:。

呆鳥雲:“以前常說,沒有困難,創造困難也要上!現在我們說, 沒有數據,創造數據,也要學!

老黃是個財務,但他不甘於只做財務,最近一直在積極學習 Python,從連 jupyter notebook 是啥都不知道,短短几個月,就已經 Pandas 上手各種玩了。

用呆鳥的話說,“ 尊重是自己掙回來的,不是別人給的。 ” 老黃這種求知若渴、積極主動的精神贏得了呆鳥的尊重。 但老黃也會遇到一些問題,且看下面的對話:

老黃: “呆鳥哥,最近感覺遇到瓶頸了,畢竟不是幹數據分析的,沒數據啊!

呆鳥: “你可以用爬蟲啊,想要啥數據就去爬。

老黃: “爬蟲還沒學呢,再說了,畢竟不是科班兒出身,Pandas 還沒學好呢,再去學爬蟲,又是一大厚本書,一時半會兒也學不會啊。 我還是想先把 Pandas 學紮實了。

呆鳥: “呃……,說的也有道理,爬蟲我也學得一知半解,而且爬蟲有風險,用起來要謹慎。 這樣吧,說說你想用啥數據,看看能不能做些模擬數據。

老黃的需求:

  1. 模擬一個超市連鎖公司的銷售訂單表

  2. 不同城市裏有不同門店,門店裏有不同銷售人員

  3. 超市銷售不同產品,每個產品對應不同的單價

  4. 生成不同訂單,對應不同客人、售貨員、分公司、產品、單價、數量、金額等

  5. 一年內每天都有不同的訂單

呆鳥的思路:

  1. 寫個字典,列出不同分公司與銷售員

  2. 寫個字典,列出不同產品與單價

當然,寫個 df 也可以,爲了直觀,這裏用的字典;

  1. 寫個隨機生成日期的函數

  2. 先生成一個空 df,再用循環生成交易日期、客戶ID、售貨員、分公司、產品、單價、數量、訂單金額。

  3. 用 DataFrame 的 append() 把每條數據加進去

這樣一來,模擬數據就成型了。用這種方式可以生成各種關係的模擬數據,還可以用 SQLAlchemy,把多個表放到模擬數據庫裏。呆鳥就曾弄過,還可以添加外鍵,可惜後來文件被誤刪除了,有興趣的朋友,自己嘗試下。

說清楚了需求,下面,我們來一步步實現:

一. 導入支持庫

import pandas as pd
import numpy as np
from datetime import datetime

二. 編寫分公司與銷售員的字典

sales_people = {"陳天浩": "上海",
                "孫健": "上海",
                "王梓戎": "廣東",
                "劉丹": "上海",
                "劉穎": "上海",
                "劉雪": "天津",
                "章洋": "上海",
                "殷琳": "廣東",
                "李輝": "北京",
                "王玉": "吉林",
                "侯寧": "上海",
                "吳中嶽": "廣東",
                "張林": "廣東",
                "莊雷": "上海",
                "王宇": "吉林",
                "利坤": "上海",
                "董丹丹": "廣東",
                "蔡建平": "山東",
                "陳楊": "吉林",
                "蔡勇": "廣東",
                "李琳": "上海",
                "魏蒼生": "天津",
                "劉帆": "天津",
                "戴雪": "上海",
                "許亮": "吉林",
                "李智童": "山東",
                "錢國": "山東",
                "郭華鋒": "吉林",
                "閻雲": "山東",
                "江敏": "上海"}

三. 編寫產品與單價對應關係的字典

products = {"蘋果": 10,
          "梨": 8,
          "桃": 6.5,
          "葡萄": 15,
          "椰子": 20,
          "西瓜": 30,
          "百香果": 12,
          "榴蓮": 50,
          "桔子": 6,
          "香蕉": 7.5}

四. 編寫隨機日期生成器

def random_dater(start_date, end_date):
    p_start_date = datetime.strptime(start_date, '%Y-%m-%d')
    p_end_date = datetime.strptime(end_date, '%Y-%m-%d')

    days_delta = p_end_date - p_start_date
    days_to_add = np.arange(0, days_delta.days)

    random_date = np.datetime64(
        start_date) + np.random.choice(days_to_add)  # numpy 也可以轉換日期

    return random_date

知識點:

  1. 這個函數的目的是,輸入起止日期,就可以返回一個在起止日期範圍內的隨機日期

  2. 計算兩個日期之間的天數, days_delta = p_end_date - p_start_date

  3. 用 np.arange() 生成一個從 0 天到間隔天數之間的數組, days_to_add = np.arange(0, days_delta.days)

  4. 隨機選擇一個數字,與開始日期相加,從而生成一個隨機日期, random_date = np.datetime64(start_date) + np.random.choice(days_to_add) ,注意這裏的 np.random.choice() 函數,就是用來隨機選擇數字的。

五. 創建帶列名的空 DataFrame

如果你還不會創建空 DataFrame,關注一下這個知識點:

sales0 = pd.DataFrame(
    columns=["交易日期", "客戶ID", "售貨員", "分公司", "產品", "單價", "數量", "訂單金額"])

六、寫個循環插入數據

for i in range(0, 10000):
    date = random_dater('2019-01-01', '2019-12-31')
    customer_id = "C" + str(np.random.randint(1, 1000)).zfill(4)
    sales_person = np.random.choice(list(sales_people))
    region = sales_people[sales_person]
    product = np.random.choice(list(products))
    price = products[product]
    quantity = np.random.randint(1, 10000)
    revenue = price * quantity
    sales0 = sales0.append(pd.Series([date, customer_id, sales_person,
                             region, product, price, quantity, revenue], index=sales0.columns), ignore_index=True)

知識點:

  1. 生成 C0001這樣的數據,用 zfill() 函數,參數4,代表4位數字 ~ 0001

  2. 生成某個範圍內的隨機整數用 np.random.randint() ,(1,1000) 代表生成的整數範圍爲 1 ~ 1000

  3. 從銷售人員字典裏隨機選擇一名銷售員, np.random.choice(list(sales_people))

  4. sales_people[sales_person] ,按銷售員姓名,提取分公司名稱

  5. sales0.append() 函數負責按生成的數據 按行 添加到 DataFrame 裏。 要往 DataFrame 裏添加行,就會用到這個函數。

這段代碼生成一萬條模擬數據,在呆鳥 13 年出品 的老電腦上,也只需要 1 分 18 秒。

七、重新排序

生成的隨機數據是亂序的,要按交易日期、分公司、售貨員排序。

sales0.sort_values(['交易日期', '分公司', '售貨員'], inplace=True)
sales0.reset_index(drop=True,inplace=True)

知識點:

  1. 按多列排序,直接寫個列名的列表就可以了,如, ['交易日期', '分公司', '售貨員']

  2. 要想排序直接生效,要用 inplace=True 參數

  3. 排序以後,索引是亂的,要重置索引,用 reset_index() 函數

  4. 拋棄之前的亂序索引,參數爲 drop=True

  5. 要想重置索引直接生效,參數爲 inplace=True

  6. 出一個小題目,自己思考下,如果想多列,按不同升降序排列,怎麼處理?

八、輸出 Excel 文件

sales0.to_excel('data/銷售明細表0.xlsx', index=False)

知識點:

  1. 輸出時不含 DataFrame 的索引,用 index=False 參數

  2. 建議使用相對路徑( 'data/銷售明細表0.xlsx' ),不要使用絕對路徑( 'd:\python\data\銷售明細表0.xlsx' ),相對路徑的好處是文件移動到別的目錄裏或分享給別人的時候,不用手動修改目錄,這就叫與人方便,與己方便!

  3. 要把數據文件與程序文件分開保存,這裏,呆鳥把 Excel 文件保存在 data 子目錄裏,注意這裏的寫法: 'data/銷售明細表0.xlsx'

至此,模擬的一萬條數據就生成了,整個代碼運行不超過 3 分鐘。

呆鳥興沖沖地找老黃報喜: “老黃,你要的模擬數據搞定啦,以後這段程序,你改改就能生成各種各樣的數據表了!

老黃: “感謝,感謝,以後再也不愁沒數據用了!

未完待續

一個小時後。 。。。

老黃鬱悶地找到呆鳥: “呆鳥哥,我想用你的代碼多生成點數據,結果一直運行不出來啊!

呆鳥: “你想要多少數據?

老黃: “100 萬條。

呆鳥: “呃(⊙o⊙)…,你真有勇氣,這樣吧,咱們再想想還有什麼辦法,能把速度加上來!

相信也會有讀者大大想到一萬條數據太少了,怎麼對得起 Pandas 的數據處理能力? 但用 append() 函數添加大量數據確實效率很低,這一點其實在 Pandas 官檔裏也提到了, 那怎麼才能提高效率呢? 效率又能提高多少呢?

相關文章