32

不会爬,没数据?没关系!3分钟搞定1w+数据,超实用!​

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzIzNTg3MDQyMQ%3D%3D&%3Bmid=2247486230&%3Bidx=2&%3Bsn=92430d9993d4a891397e47f497b72637
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
呆鸟云:“以前常说,没有困难,创造困难也要上!现在我们说, 没有数据,创造数据,也要学!

老黄是个财务,但他不甘于只做财务,最近一直在积极学习 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 秒。

fQvmyy6.png!web

七、重新排序

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

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 官档里也提到了, 那怎么才能提高效率呢? 效率又能提高多少呢?


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK