美文网首页AI人工智能与数学之美
Pandas高效的生成测试数据

Pandas高效的生成测试数据

作者: 羋学僧 | 来源:发表于2020-04-15 17:39 被阅读0次

方案一

使用 DataFrame 的 append()

1. 导入支持库

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

2. 编写分公司与销售员的字典

sales_people = {"陈天浩": "上海",
                "孙健": "上海",
                "王梓戎": "广东",
                "刘丹": "上海",
                "刘颖": "上海",
                "刘雪": "天津",
                "章洋": "上海",
                "殷琳": "广东",
                "李辉": "北京",
                "王玉": "吉林",
                "侯宁": "上海",
                "吴中岳": "广东",
                "张林": "广东",
                "庄雷": "上海",
                "王宇": "吉林",
                "利坤": "上海",
                "董丹丹": "广东",
                "蔡建平": "山东",
                "陈杨": "吉林",
                "蔡勇": "广东",
                "李琳": "上海",
                "魏苍生": "天津",
                "刘帆": "天津",
                "戴雪": "上海",
                "许亮": "吉林",
                "李智童": "山东",
                "钱国": "山东",
                "郭华锋": "吉林",
                "阎云": "山东",
                "江敏": "上海"}

3. 编写产品与单价对应关系的字典

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

4. 编写随机日期生成器

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() 函数,就是用来随机选择数字的。

5. 创建带列名的空 DataFrame

如果你还不会创建空 DataFrame,关注一下这个知识点:

sales0 = pd.DataFrame(
    columns=["交易日期", "客户ID", "售货员", "分公司", "产品", "单价", "数量", "订单金额"])

6、写个循环插入数据

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 秒。

7、重新排序

生成的随机数据是乱序的,要按交易日期、分公司、售货员排序。

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. 出一个小题目,自己思考下,如果想多列,按不同升降序排列,怎么处理?

方案二

生成 100 万条模拟数据,呆鸟先测试了一下 10 万条。结果不是想象中的 1 分钟 18 秒乘以 10 的概念,而是运行了55 分钟,运行耗时增加了 40 多倍。要是 100 万条,就算不考虑数据越大,速度越慢的前提,哪怕只在 10 万条耗时的基础上提高 40 倍,那也要 2200 分钟。官网上确实也说了 DataFrame 的 append() 函数操作的数据量越大,耗费的时间就越长

def get_counterpart(counterpart_dict, source):
    counterpart = counterpart_dict[source]
    return counterpart

sales2 = pd.DataFrame(columns=["交易日期","客户ID","售货员","分公司","产品","单价","数量","订单金额"], index=range(1000000))

sales2['交易日期'] = sales2['交易日期'].apply(lambda row: random_dater('2019-01-01', '2019-12-31'))
sales2['客户ID'] = sales2['客户ID'].apply(lambda row: "C" + str(np.random.randint(1, 1000)).zfill(4))
sales2['售货员'] = sales2['售货员'].apply(lambda row: np.random.choice(list(sales_people)))
sales2['分公司'] = sales2.apply(lambda row: get_counterpart(sales_people, row["售货员"]), axis=1)
sales2['产品'] = sales2['产品'].apply(lambda row: np.random.choice(list(products)))
sales2['单价'] = sales2.apply(lambda row: get_counterpart(products, row["产品"]), axis=1)
sales2['数量'] = sales2['数量'].apply(lambda row: np.random.randint(1, 10000))
sales2['订单金额'] = sales2['单价'] * sales2['数量']

生成 100 万条数据只用了不到 3 分钟!

知识点:

1.生成一个长度为 100 万条的空 DataFrame,见 index=range(1000000)
2.总体思路为使用 apply() 函数,配合 lambda 匿名函数,再生成每列数据;
3.为了配合lambda, 还要写个函数,见下方代码,该函数通过字典的键获取字典的值;

def get_counterpart(counterpart_dict, source):
    counterpart = counterpart_dict[source]
    return counterpart

注意:这段代码,除了使用了apply() + lambda,计算方式本身并没有特别的变化。

方案三

sale = []
for i in range(0, 100000):
    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
    sale.append([date, customer_id, sales_person,
                 region, product, price, quantity, revenue])
sales3 = pd.DataFrame(sale,columns=["交易日期","客户ID","售货员","分公司","产品","单价","数量","订单金额"])

大家可以看到,生成 10 万条数据只用了 12 秒,比初始方案的速度提升了 275 倍。

生成 100 万条数据也只需要 1 分钟 52 秒。这比用初始方案生成 100 万模拟数据估算的耗时 2200 分钟,足足快了 1178 倍

知识点:

与方案一相比,这段代码的区别在于,生成一个空列表,再把添加了数据的列表转换成 DataFrame,除此之外,别的都一样。

学习来源1

学习来源2

相关文章

网友评论

    本文标题:Pandas高效的生成测试数据

    本文链接:https://www.haomeiwen.com/subject/iufhvhtx.html