├── .gitignore
├── Answers
├── week1-challenge-01
│ └── read_challenge.py
├── week1-challenge-02
│ └── sql_challenge.py
├── week1-challenge-03
│ └── github_data.py
├── week1-challenge-04
│ └── shiyanlou_user.py
├── week1-challenge-05
│ ├── scrapy.cfg
│ └── shiyanlou
│ │ ├── __init__.py
│ │ ├── items.py
│ │ ├── middlewares.py
│ │ ├── pipelines.py
│ │ ├── settings.py
│ │ └── spiders
│ │ ├── __init__.py
│ │ ├── github.py
│ │ └── github_next_page.py
├── week2-challenge-01
│ └── titanic.py
├── week2-challenge-02
│ └── earthquake.py
├── week2-challenge-03
│ └── earthquake.py
├── week2-challenge-04
│ ├── carbon_dioxide.py
│ └── carbon_dioxide_2.py
├── week2-challenge-05
│ └── carbon_gdp.py
├── week3-challenge-01
│ └── ols_matrix.py
├── week3-challenge-02
│ └── houseprice.py
├── week3-challenge-03
│ └── linear_regression.py
├── week3-challenge-04
│ └── 手写字符分类预测.ipynb
├── week3-challenge-05
│ └── 使用聚类压缩图像.ipynb
├── week4-challenge-01
│ └── banknote.py
├── week4-challenge-02
│ └── association.py
├── week4-challenge-03
│ └── google_stock.py
├── week4-challenge-04
│ └── production_index.py
├── week4-challenge-05
│ └── chengdu_pm25.py
├── week5-spiders-01
│ └── lianjia_spider.py
└── week5-spiders-02
│ ├── create_sqlite_database.py
│ ├── insert_database.py
│ └── xiecheng_spider.py
├── Assignments
├── README.md
├── 🏅️dm01-stenphen-中国保险业过去五年基础数据分析.ipynb
├── 🏅️dm02-米竹314159-杭州互联网寒冬背景下的数据分析岗现状分析.ipynb
├── 🏅️dm04-Luo2019-链家成都市区挂牌二手房分析.ipynb
├── 🥈dm01-BellaG-上海历史天气数据分析预测.ipynb
├── 🥈dm02-linnecn-医学专业论坛的数据爬取和分析.ipynb
├── 🥈dm04-Yueyec-B-站番剧数据简单分析.ipynb
└── 🥉dm01-hcccom-双色球历史数据统计预测.ipynb
├── LICENSE
├── Mindmaps
├── README.md
├── louplus-dm-week1.png
├── louplus-dm-week2.png
├── louplus-dm-week3.png
├── louplus-dm-week4.png
└── louplus-dm-week5.png
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 | .DS_Store
106 |
--------------------------------------------------------------------------------
/Answers/week1-challenge-01/read_challenge.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | def convert(file):
4 | df = pd.read_json(file)
5 | df1000 = df[:1000]
6 | df1000.to_hdf('user_study.h5', key='data')
--------------------------------------------------------------------------------
/Answers/week1-challenge-02/sql_challenge.py:
--------------------------------------------------------------------------------
1 | import sqlite3
2 | import pandas as pd
3 |
4 | def count(file, user_id):
5 |
6 | sql_con = sqlite3.connect(file)
7 | sql_query = "SELECT * FROM data WHERE user_id == {}".format(user_id)
8 | df = pd.read_sql(sql_query, sql_con)
9 |
10 | if len(df)==0:
11 | return 0
12 | else:
13 | sum_minutes = df.minutes.sum()
14 | return sum_minutes
--------------------------------------------------------------------------------
/Answers/week1-challenge-03/github_data.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import pandas as pd
3 |
4 | def issues(repo):
5 | url = "https://api.github.com/repos/{}/issues".format(repo)
6 | issues = requests.get(url)
7 |
8 | issues_list = []
9 | for issue in issues.json():
10 | issues_dict = {'number':issue['number'],
11 | 'title':issue['title'],
12 | 'user_name':issue['user']['login']}
13 | issues_list.append(issues_dict)
14 |
15 | issues_df = pd.DataFrame(issues_list)
16 |
17 | return issues_df
18 |
19 | issues("numpy/numpy")
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Answers/week1-challenge-04/shiyanlou_user.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from lxml import html
3 |
4 |
5 | def user_info(user_id):
6 |
7 | url = "https://www.lanqiao.cn/users/{}/".format(user_id)
8 | content = requests.get(url)
9 |
10 | if content.status_code == 200:
11 | tree = html.fromstring(content.text)
12 | # 首先选取所以 div 元素,要求其 class 属性中包含 name 字段
13 | # 再取 div 下的 span
14 | user_name = tree.xpath("//div[contains(@class, 'name')]/span/text()")[0].strip()
15 | user_level = tree.xpath("//div[contains(@class, 'name')]/span/text()")[1].strip()[1:]
16 | return user_name, int(user_level)
17 | else:
18 | user_name, user_level = (None, None)
19 | return user_name, user_level
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/scrapy.cfg:
--------------------------------------------------------------------------------
1 | # Automatically created by: scrapy startproject
2 | #
3 | # For more information about the [deploy] section see:
4 | # https://scrapyd.readthedocs.io/en/latest/deploy.html
5 |
6 | [settings]
7 | default = shiyanlou.settings
8 |
9 | [deploy]
10 | #url = http://localhost:6800/
11 | project = shiyanlou
12 |
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/shiyanlou/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiyanlou/louplus-dm/52764983b7080c3ca760e38c38c9a71cf0c2ed3e/Answers/week1-challenge-05/shiyanlou/__init__.py
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/shiyanlou/items.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Define here the models for your scraped items
4 | #
5 | # See documentation in:
6 | # https://doc.scrapy.org/en/latest/topics/items.html
7 |
8 | import scrapy
9 |
10 |
11 | class ShiyanlouItem(scrapy.Item):
12 | # define the fields for your item here like:
13 | # name = scrapy.Field()
14 | repo_name = scrapy.Field() # repo 名称
15 | update_time = scrapy.Field() # 更新时间
16 |
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/shiyanlou/middlewares.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Define here the models for your spider middleware
4 | #
5 | # See documentation in:
6 | # https://doc.scrapy.org/en/latest/topics/spider-middleware.html
7 |
8 | from scrapy import signals
9 |
10 |
11 | class ShiyanlouSpiderMiddleware(object):
12 | # Not all methods need to be defined. If a method is not defined,
13 | # scrapy acts as if the spider middleware does not modify the
14 | # passed objects.
15 |
16 | @classmethod
17 | def from_crawler(cls, crawler):
18 | # This method is used by Scrapy to create your spiders.
19 | s = cls()
20 | crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
21 | return s
22 |
23 | def process_spider_input(self, response, spider):
24 | # Called for each response that goes through the spider
25 | # middleware and into the spider.
26 |
27 | # Should return None or raise an exception.
28 | return None
29 |
30 | def process_spider_output(self, response, result, spider):
31 | # Called with the results returned from the Spider, after
32 | # it has processed the response.
33 |
34 | # Must return an iterable of Request, dict or Item objects.
35 | for i in result:
36 | yield i
37 |
38 | def process_spider_exception(self, response, exception, spider):
39 | # Called when a spider or process_spider_input() method
40 | # (from other spider middleware) raises an exception.
41 |
42 | # Should return either None or an iterable of Response, dict
43 | # or Item objects.
44 | pass
45 |
46 | def process_start_requests(self, start_requests, spider):
47 | # Called with the start requests of the spider, and works
48 | # similarly to the process_spider_output() method, except
49 | # that it doesn’t have a response associated.
50 |
51 | # Must return only requests (not items).
52 | for r in start_requests:
53 | yield r
54 |
55 | def spider_opened(self, spider):
56 | spider.logger.info('Spider opened: %s' % spider.name)
57 |
58 |
59 | class ShiyanlouDownloaderMiddleware(object):
60 | # Not all methods need to be defined. If a method is not defined,
61 | # scrapy acts as if the downloader middleware does not modify the
62 | # passed objects.
63 |
64 | @classmethod
65 | def from_crawler(cls, crawler):
66 | # This method is used by Scrapy to create your spiders.
67 | s = cls()
68 | crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
69 | return s
70 |
71 | def process_request(self, request, spider):
72 | # Called for each request that goes through the downloader
73 | # middleware.
74 |
75 | # Must either:
76 | # - return None: continue processing this request
77 | # - or return a Response object
78 | # - or return a Request object
79 | # - or raise IgnoreRequest: process_exception() methods of
80 | # installed downloader middleware will be called
81 | return None
82 |
83 | def process_response(self, request, response, spider):
84 | # Called with the response returned from the downloader.
85 |
86 | # Must either;
87 | # - return a Response object
88 | # - return a Request object
89 | # - or raise IgnoreRequest
90 | return response
91 |
92 | def process_exception(self, request, exception, spider):
93 | # Called when a download handler or a process_request()
94 | # (from other downloader middleware) raises an exception.
95 |
96 | # Must either:
97 | # - return None: continue processing this exception
98 | # - return a Response object: stops process_exception() chain
99 | # - return a Request object: stops process_exception() chain
100 | pass
101 |
102 | def spider_opened(self, spider):
103 | spider.logger.info('Spider opened: %s' % spider.name)
104 |
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/shiyanlou/pipelines.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Define your item pipelines here
4 | #
5 | # Don't forget to add your pipeline to the ITEM_PIPELINES setting
6 | # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
7 | import pandas as pd
8 |
9 | class ShiyanlouPipeline(object):
10 |
11 | def process_item(self, item, spider):
12 | # 读取 item 数据
13 | repo_name = item['repo_name']
14 | update_time = item['update_time']
15 | # 每条数据组成临时 df_temp
16 | df_temp = pd.DataFrame([[repo_name, update_time]], columns=['repo_name', 'update_time'])
17 | # 将 df_temp 合并到 df
18 | self.df = self.df.append(df_temp, ignore_index=True).sort_values(by=['update_time'], ascending=False)
19 |
20 | return item
21 |
22 | #当爬虫启动时
23 | def open_spider(self, spider):
24 | # 新建一个带列名的空白 df
25 | self.df = pd.DataFrame(columns=['repo_name', 'update_time'])
26 |
27 | # 当爬虫关闭时
28 | def close_spider(self, spider):
29 | # 将 df 存储为 csv 文件
30 | pd.DataFrame.to_csv(self.df, "../shiyanlou_repo.csv")
31 |
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/shiyanlou/settings.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Scrapy settings for shiyanlou project
4 | #
5 | # For simplicity, this file contains only settings considered important or
6 | # commonly used. You can find more settings consulting the documentation:
7 | #
8 | # https://doc.scrapy.org/en/latest/topics/settings.html
9 | # https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
10 | # https://doc.scrapy.org/en/latest/topics/spider-middleware.html
11 |
12 | BOT_NAME = 'shiyanlou'
13 |
14 | SPIDER_MODULES = ['shiyanlou.spiders']
15 | NEWSPIDER_MODULE = 'shiyanlou.spiders'
16 |
17 |
18 | # Crawl responsibly by identifying yourself (and your website) on the user-agent
19 | #USER_AGENT = 'shiyanlou (+http://www.yourdomain.com)'
20 |
21 | # Obey robots.txt rules
22 | ROBOTSTXT_OBEY = False
23 |
24 | # Configure maximum concurrent requests performed by Scrapy (default: 16)
25 | #CONCURRENT_REQUESTS = 32
26 |
27 | # Configure a delay for requests for the same website (default: 0)
28 | # See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
29 | # See also autothrottle settings and docs
30 | # DOWNLOAD_DELAY = 3
31 | # The download delay setting will honor only one of:
32 | #CONCURRENT_REQUESTS_PER_DOMAIN = 16
33 | #CONCURRENT_REQUESTS_PER_IP = 16
34 |
35 | # Disable cookies (enabled by default)
36 | #COOKIES_ENABLED = False
37 |
38 | # Disable Telnet Console (enabled by default)
39 | #TELNETCONSOLE_ENABLED = False
40 |
41 | # Override the default request headers:
42 | #DEFAULT_REQUEST_HEADERS = {
43 | # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
44 | # 'Accept-Language': 'en',
45 | #}
46 |
47 | # Enable or disable spider middlewares
48 | # See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
49 | #SPIDER_MIDDLEWARES = {
50 | # 'shiyanlou.middlewares.ShiyanlouSpiderMiddleware': 543,
51 | #}
52 |
53 | # Enable or disable downloader middlewares
54 | # See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
55 | #DOWNLOADER_MIDDLEWARES = {
56 | # 'shiyanlou.middlewares.ShiyanlouDownloaderMiddleware': 543,
57 | #}
58 |
59 | # Enable or disable extensions
60 | # See https://doc.scrapy.org/en/latest/topics/extensions.html
61 | #EXTENSIONS = {
62 | # 'scrapy.extensions.telnet.TelnetConsole': None,
63 | #}
64 |
65 | # Configure item pipelines
66 | # See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
67 | ITEM_PIPELINES = {
68 | 'shiyanlou.pipelines.ShiyanlouPipeline': 300,
69 | }
70 |
71 | # Enable and configure the AutoThrottle extension (disabled by default)
72 | # See https://doc.scrapy.org/en/latest/topics/autothrottle.html
73 | #AUTOTHROTTLE_ENABLED = True
74 | # The initial download delay
75 | #AUTOTHROTTLE_START_DELAY = 5
76 | # The maximum download delay to be set in case of high latencies
77 | #AUTOTHROTTLE_MAX_DELAY = 60
78 | # The average number of requests Scrapy should be sending in parallel to
79 | # each remote server
80 | #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
81 | # Enable showing throttling stats for every response received:
82 | #AUTOTHROTTLE_DEBUG = False
83 |
84 | # Enable and configure HTTP caching (disabled by default)
85 | # See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
86 | #HTTPCACHE_ENABLED = True
87 | #HTTPCACHE_EXPIRATION_SECS = 0
88 | #HTTPCACHE_DIR = 'httpcache'
89 | #HTTPCACHE_IGNORE_HTTP_CODES = []
90 | #HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
91 |
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/shiyanlou/spiders/__init__.py:
--------------------------------------------------------------------------------
1 | # This package will contain the spiders of your Scrapy project
2 | #
3 | # Please refer to the documentation for information on how to create and manage
4 | # your spiders.
5 |
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/shiyanlou/spiders/github.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import scrapy
3 | from shiyanlou.items import ShiyanlouItem
4 |
5 |
6 | class GithubSpider(scrapy.Spider):
7 | name = 'github'
8 | allowed_domains = ['github.com']
9 |
10 | @property
11 | def start_urls(self):
12 | url_temp = 'https://github.com/shiyanlou?after={}&tab=repositories'
13 | # 此参考会失效,请自行重新手动复制 after 参数
14 | after = [
15 | '',
16 | 'Y3Vyc29yOnYyOpK5MjAxNy0wNi0wN1QwNjoxOTo1NyswODowMM4FkpYw',
17 | 'Y3Vyc29yOnYyOpK5MjAxNS0wMS0yNVQxMTozMTowNyswODowMM4Bxrsx',
18 | 'Y3Vyc29yOnYyOpK5MjAxNC0xMS0yMFQxMzowMzo1MiswODowMM4BjkvL',
19 | ]
20 | return (url_temp.format(i) for i in after) # 1-4 页
21 |
22 | def parse(self, response):
23 | repos = response.xpath('//li[@itemprop="owns"]')
24 | for repo in repos:
25 | item = ShiyanlouItem()
26 | item['repo_name'] = repo.xpath(".//a[@itemprop='name codeRepository']/text()").extract_first().strip()
27 | item['update_time'] = repo.xpath(".//relative-time/@datetime").extract_first()
28 |
29 | yield item
--------------------------------------------------------------------------------
/Answers/week1-challenge-05/shiyanlou/spiders/github_next_page.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import scrapy
3 | from shiyanlou.items import ShiyanlouItem
4 |
5 |
6 | class GithubSpider(scrapy.Spider):
7 | name = 'github_next_page'
8 | allowed_domains = ['github.com']
9 |
10 | @property
11 | def start_urls(self):
12 | return ('https://github.com/shiyanlou?tab=repositories', )
13 |
14 | def parse(self, response):
15 | repos = response.xpath('//li[@itemprop="owns"]')
16 | for repo in repos:
17 | item = ShiyanlouItem()
18 | item['repo_name'] = repo.xpath(".//a[@itemprop='name codeRepository']/text()").extract_first().strip()
19 | item['update_time'] = repo.xpath(".//relative-time/@datetime").extract_first()
20 |
21 | yield item
22 |
23 | # 如果 Next 按钮没被禁用,那么表示有下一页
24 | spans = response.css('div.pagination span.disabled::text')
25 | if len(spans) == 0 or spans[-1].extract() != 'Next':
26 | next_url = response.css('div.paginate-container a:last-child::attr(href)').extract_first()
27 | yield response.follow(next_url, callback=self.parse)
28 |
--------------------------------------------------------------------------------
/Answers/week2-challenge-01/titanic.py:
--------------------------------------------------------------------------------
1 | from matplotlib import pyplot as plt
2 | import seaborn as sns
3 |
4 | def plot():
5 | df = sns.load_dataset("titanic")
6 |
7 | fig, axes = plt.subplots(ncols=3, nrows=1, figsize=(15,4))
8 |
9 | sns.distplot(df.age.dropna(), ax=axes[0])
10 | sns.countplot(x='sex', hue="alive", data=df, ax=axes[1])
11 | sns.countplot(x="class", hue="alive", data=df, ax=axes[2])
12 |
13 | return axes
--------------------------------------------------------------------------------
/Answers/week2-challenge-02/earthquake.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 |
4 | def clean():
5 | # 读取据
6 | df = pd.read_csv("earthquake.csv")
7 | # 选择需保留列
8 | df1 = df[['time', 'latitude', 'longitude', 'depth', 'mag']]
9 | # 对 place 列使用分割,得到需要的 region 数据
10 | place = df.place.str.split(', ').tolist()
11 | region = []
12 | for row in place:
13 | region.append(row[-1])
14 | df2 = pd.DataFrame(region, columns=['region'])
15 | # 拼接数据
16 | df = pd.concat([df1, df2], axis=1)
17 | # 去除重复值
18 | df_clean = df.drop_duplicates().dropna()
19 |
20 | return df_clean
--------------------------------------------------------------------------------
/Answers/week2-challenge-03/earthquake.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 |
4 | def clean():
5 | # 读取据
6 | df = pd.read_csv("earthquake.csv")
7 | # 选择需保留列
8 | df1 = df[['time', 'latitude', 'longitude', 'depth', 'mag']]
9 | # 对 place 列使用分割,得到需要的 region 数据
10 | place = df.place.str.split(', ').tolist()
11 | region = []
12 | for row in place:
13 | region.append(row[-1])
14 | df2 = pd.DataFrame(region, columns=['region'])
15 | # 拼接数据
16 | df = pd.concat([df1, df2], axis=1)
17 | # 去除重复值
18 | df_clean = df.drop_duplicates().dropna()
19 |
20 | return df_clean
21 |
22 |
23 | def mag_region():
24 | # 加载清洁后数据
25 | df_clean = clean()
26 | # 数据离散化,注意开闭区间
27 | df_clean['mag'] = pd.cut(df_clean.mag, bins=[0, 2, 5, 7, 9, 15], right=False, labels=[
28 | 'micro', 'light', 'strong', 'major', 'great'])
29 |
30 | print(df_clean)
31 | # 多索引分组聚合并计数
32 | df_group = df_clean.groupby(by=['mag', 'region']).count()
33 | # 重置索引并去除缺失值
34 | df_reindex = df_group.reset_index().dropna()
35 | # 按计数从大到小排序,并使用去除重复值的方法巧妙地保留下各地区最大值
36 | df_sort = df_reindex.sort_values(
37 | by='time', ascending=False).drop_duplicates(['mag'])
38 | # 按题目要求整理并重命名
39 | df_final = df_sort.set_index('mag')[['region', 'time']].rename(
40 | columns={"time": "times"})
41 | # 按题目要求将计数处理成 int 类型
42 | df_final['times'] = df_final.times.astype('int')
43 |
44 | return df_final
45 |
--------------------------------------------------------------------------------
/Answers/week2-challenge-04/carbon_dioxide.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 |
4 | def data_clean():
5 | '''data_clean() 函数用于数据清洁,大致步骤如下:
6 | 1. 统一设置国家代码为新索引
7 | 2. 去掉多余的数据列
8 | 3. 将不规范空值替换为 NaN,并进行填充
9 | '''
10 | # 读取数据文件
11 | df_data = pd.read_excel("ClimateChange.xlsx", sheetname='Data')
12 | df_country = pd.read_excel("ClimateChange.xlsx", sheetname='Country')
13 |
14 | # 处理 data 数据表
15 | # 选取 EN.ATM.CO2E.KT 数据,并将国家代码设置为索引
16 | df_data_reindex = df_data[df_data['Series code']== 'EN.ATM.CO2E.KT'].set_index('Country code')
17 | # 剔除不必要的数据列
18 | df_data_drop = df_data_reindex.drop(labels=['Country name', 'Series code', 'Series name', 'SCALE', 'Decimals'], axis=1)
19 | # 将原数据集中不规范的空值替换为 NaN 方便填充
20 | df_data_nan = df_data_drop.replace({'..': pd.np.NaN})
21 | # 对 NaN 空值进行向前和向后填充
22 | df_data_fill = df_data_nan.fillna(method='ffill', axis=1).fillna(method='bfill', axis=1)
23 | # 对填充后依旧全部为空值的数据行进行剔除
24 | df_data_dropna = df_data_fill.dropna(how='all')
25 |
26 | # 处理 Country 数据表
27 | # 将国家代码设置为索引
28 | df_country_reindex = pd.DataFrame(df_country).set_index('Country code')
29 | # 剔除不必要的数据列
30 | df_country_drop = df_country_reindex.drop(labels=['Capital city', 'Region', 'Lending category'], axis=1)
31 |
32 | # 合并数据表
33 | # 对 Data 和 Country 表按照索引进行合并
34 | df_combine = pd.concat([df_data_dropna, df_country_drop], axis=1)
35 | # 对合并后数据集进行求和得到各国排放总量
36 | df_combine['Sum emissions'] = df_combine[list(df_combine)[:-2]].sum(axis=1)
37 | # 对合并后存在空值的数据行进行剔除,得到清洁后的数据集
38 | df_clean = df_combine.dropna(thresh=10)
39 |
40 | return df_clean
41 |
42 | def co2():
43 | '''co2() 函数用于数据统计,大致步骤如下:
44 | 1. 使用 groupby 按题目规则求和
45 | 2. 对数据进行排序并得到目标 DataFrame
46 | '''
47 | # 读取清洁后数据
48 | df_clean = data_clean()
49 |
50 | # 按收入群体对数据进行求和
51 | sum_by_groups = df_clean.groupby('Income group')['Sum emissions'].sum()
52 |
53 | # 按要求整理 DataFrame
54 | item_high_list = []
55 | item_low_list = []
56 |
57 | for group_name in list(sum_by_groups.index):
58 | # 得到各收入群体最高排放量数据
59 | item_high = df_clean[df_clean['Income group'] == group_name].sort_values(by='Sum emissions', ascending=False).iloc[0]
60 | # 将最高排放量数据存入相应列表方便生成最终 DataFrame
61 | item_high_list.append((item_high['Income group'], item_high['Country name'], item_high['Sum emissions']))
62 | # 得到各收入群体最低排放量数据
63 | item_low = df_clean[df_clean['Income group'] == group_name].sort_values(by='Sum emissions').iloc[0]
64 | # 将最低排放量数据存入相应列表方便生成最终 DataFrame
65 | item_low_list.append((item_low['Income group'], item_low['Country name'], item_low['Sum emissions']))
66 |
67 | # 设置 DataFrame 标签
68 | high_labels = ['Income group', 'Highest emission country', 'Highest emissions']
69 | low_labels = ['Income group', 'Lowest emission country', 'Lowest emissions']
70 |
71 | # 生成并合并目标 DataFrame
72 | highest_df = pd.DataFrame.from_records(item_high_list, columns=high_labels).set_index('Income group')
73 | lowest_df = pd.DataFrame.from_records(item_low_list, columns=low_labels).set_index('Income group')
74 |
75 | results = pd.concat([sum_by_groups, highest_df, lowest_df], axis=1)
76 |
77 | return results
--------------------------------------------------------------------------------
/Answers/week2-challenge-04/carbon_dioxide_2.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 |
4 | def data_clean():
5 | data = pd.read_excel("ClimateChange.xlsx", sheetname='Data')
6 |
7 | # 处理 data 数据表 # 选取 EN.ATM.CO2E.KT 数据,并将国家代码设置为索引
8 | data = data[data['Series code'] ==
9 | 'EN.ATM.CO2E.KT'].set_index('Country code')
10 | # 剔除不必要的数据列
11 | data.drop(labels=['Country name', 'Series code',
12 | 'Series name', 'SCALE', 'Decimals'], axis=1, inplace=True)
13 | # 将原数据集中不规范的空值替换为 NaN 方便填充
14 | data.replace({'..': pd.np.NaN}, inplace=True)
15 | # 对 NaN 空值进行向前和向后填充
16 | data = data.fillna(method='ffill', axis=1).fillna(method='bfill', axis=1)
17 | # 对填充后依旧全部为空值的数据行进行剔除
18 | data.dropna(how='all', inplace=True)
19 | data['Sum emissions'] = data.sum(axis=1)
20 | data = data['Sum emissions']
21 |
22 | # 处理 Country 数据表
23 | # 将国家代码设置为索引
24 | countries = pd.read_excel("ClimateChange.xlsx", sheetname='Country')
25 | countries.set_index('Country code', inplace=True)
26 | # 剔除不必要的数据列
27 | countries.drop(labels=['Capital city', 'Region',
28 | 'Lending category'], axis=1, inplace=True)
29 |
30 | # 合并数据表
31 | # 对 Data 和 Country 表按照索引进行合并
32 | return pd.concat([data, countries], axis=1)
33 |
34 |
35 | def co2():
36 | '''co2() 函数用于数据统计,大致步骤如下:
37 | 1. 使用 grouby 按题目规则求和
38 | 2. 对数据进行排序并得到目标 DataFrame
39 | '''
40 | # 读取清洁后数据
41 | df = data_clean()
42 |
43 | # 按收入群体对数据进行求和
44 | df_sum = df.groupby('Income group').sum()
45 |
46 | df_max = df.sort_values(by='Sum emissions', ascending=False).groupby(
47 | 'Income group').head(1).set_index('Income group')
48 | df_max.columns = ['Highest emissions', 'Highest emission country']
49 | df_max = df_max.reindex(
50 | columns=['Highest emission country', 'Highest emissions'])
51 |
52 | df_min = df.sort_values(by='Sum emissions').groupby(
53 | 'Income group').head(1).set_index('Income group')
54 | df_min.columns = ['Lowest emissions', 'Lowest emission country']
55 | df_min = df_min.reindex(
56 | columns=['Lowest emission country', 'Lowest emissions'])
57 |
58 | result = pd.concat([df_sum, df_max, df_min], axis=1)
59 |
60 | return result
--------------------------------------------------------------------------------
/Answers/week2-challenge-05/carbon_gdp.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 | from matplotlib import pyplot as plt
4 |
5 |
6 | def data_clean():
7 | '''data_clean() 函数用于数据清洁,大致步骤如下:
8 | 1. 统一设置国家代码为新索引
9 | 2. 去掉多余的数据列
10 | 3. 将不规范空值替换为 NaN,并进行填充
11 | '''
12 | # 读取数据
13 | df_data = pd.read_excel("ClimateChange.xlsx", sheetname='Data')
14 |
15 | # 选择数据
16 | df_co2 = df_data[df_data['Series code'] ==
17 | 'EN.ATM.CO2E.KT'].set_index('Country code')
18 | df_gdp = df_data[df_data['Series code'] ==
19 | 'NY.GDP.MKTP.CD'].set_index('Country code')
20 |
21 | # 缺失值替换
22 | df_co2_nan = df_co2.replace({'..': pd.np.NaN})
23 | df_gdp_nan = df_gdp.replace({'..': pd.np.NaN})
24 |
25 | # 缺失值填充
26 | df_co2_fill = df_co2_nan.iloc[:, 5:].fillna(
27 | method='ffill', axis=1).fillna(method='bfill', axis=1)
28 | df_gdp_fill = df_gdp_nan.iloc[:, 5:].fillna(
29 | method='ffill', axis=1).fillna(method='bfill', axis=1)
30 |
31 | # 数据合并
32 | df_co2_fill['CO2-SUM'] = df_co2_fill.sum(axis=1)
33 | df_gdp_fill['GDP-SUM'] = df_gdp_fill.sum(axis=1)
34 | df_merge = pd.concat([df_co2_fill['CO2-SUM'], df_gdp_fill['GDP-SUM']], axis=1)
35 |
36 | # 缺失数据填充为 0
37 | df_merge_fill = df_merge.fillna(value=0)
38 |
39 | return df_merge_fill
40 |
41 |
42 | def co2_gdp_plot():
43 | '''co2_gdp_plot() 函数用于数据整理和绘图,大致步骤如下:
44 | 1. 数据归一化
45 | 2. 得到需要返回的数据
46 | 3. 绘图
47 | '''
48 | # 读取数据
49 | df_clean = data_clean()
50 |
51 | # 数据归一化处理
52 | df_max_min = (df_clean - df_clean.min()) / (df_clean.max() - df_clean.min())
53 |
54 | # 获取中国归一化后的 CO2 和 GDP 数据
55 | china = []
56 | for i in df_max_min[df_max_min.index == 'CHN'].values:
57 | china.extend(np.round(i, 3).tolist())
58 |
59 | # 获取 5 个常任理事国标签及对应的坐标刻度
60 | countries_labels = ['USA', 'CHN', 'FRA', 'RUS', 'GBR']
61 | # 获取国家标签作为刻度标签
62 | sticks_labels = []
63 | # 获取相应国家序号对应着刻度坐标
64 | labels_position = []
65 |
66 | for i in range(len(df_max_min)):
67 | if df_max_min.index[i] in countries_labels:
68 | sticks_labels.append(df_max_min.index[i])
69 | labels_position.append(i)
70 |
71 | # 对数据进行绘图
72 | fig, axes = plt.subplots()
73 | df_max_min.plot(
74 | kind='line',
75 | title='GDP-CO2',
76 | ax=axes
77 | )
78 | plt.xlabel("Countries")
79 | plt.ylabel("Values")
80 | # 绘制 5 大常任理事国坐标刻度标签
81 | plt.xticks(labels_position, sticks_labels, rotation='vertical')
82 | plt.show()
83 |
84 | return axes, china
--------------------------------------------------------------------------------
/Answers/week3-challenge-01/ols_matrix.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 |
4 |
5 | def caculate_w():
6 |
7 | # 读取数据集
8 | df = pd.read_csv("nyc-east-river-bicycle-counts.csv", index_col=0)
9 |
10 | # 处理自变量
11 | x = df['Brooklyn Bridge'].values
12 | x = x.reshape(len(x), 1) # 添加截距项系数
13 | x = np.matrix(np.concatenate((np.ones_like(x), x), axis=1))
14 |
15 | # 处理因变量
16 | y = df['Manhattan Bridge'].values
17 | y = np.matrix(y.reshape(len(y), 1))
18 |
19 | # 使用矩阵方法计算
20 | W = (x.T * x).I * x.T * y
21 | b = round(float(W[0]), 2)
22 | w = round(float(W[1]), 2)
23 |
24 | return w, b
25 |
--------------------------------------------------------------------------------
/Answers/week3-challenge-02/houseprice.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | import numpy as np
3 | from sklearn.preprocessing import PolynomialFeatures
4 | from sklearn.linear_model import LinearRegression
5 | from sklearn.metrics import mean_absolute_error
6 | from sklearn.model_selection import train_test_split
7 |
8 |
9 | def beijing(n):
10 |
11 | # 读取数据,去除重复值,无空值
12 | df = pd.read_csv("beijing_house_price.csv")
13 | df = df.drop_duplicates()
14 | # df = df[['公交', '写字楼', '医院', '商场', '地铁', '学校', '建造时间', '楼层', '面积', '每平米价格']]
15 | df = df.iloc[:, [0, 1, 2, 3, 4, 5, 7, 9, 11, 10]] # 线上环境中文输入不方便
16 |
17 | # 计算特征与目标值相关性系数,并保留前 3 个特征
18 | pearson = np.abs(df.corr(method='pearson').iloc[-1])
19 | pearson_max = pearson.sort_values(ascending=False)[1:4]
20 | features_names = pearson_max.index.values
21 | features = df[features_names]
22 | # target = df['每平米价格']
23 | target = df.iloc[:, [9]]
24 |
25 | # 切分训练和测试数据
26 | X_train, X_test, y_train, y_test = train_test_split(
27 | features, target, test_size=0.3, random_state=10)
28 |
29 | # 多项式特征处理
30 | poly_features = PolynomialFeatures(degree=n)
31 | X_train_features = poly_features.fit_transform(X_train)
32 | X_test_features = poly_features.fit_transform(X_test)
33 |
34 | # 建立线性回归模型
35 | model = LinearRegression()
36 | model.fit(X_train_features, y_train)
37 | y_pred = model.predict(X_test_features)
38 |
39 | # 计算平均绝对误差
40 | mae = mean_absolute_error(y_test, y_pred)
41 |
42 | return mae
43 |
--------------------------------------------------------------------------------
/Answers/week3-challenge-03/linear_regression.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 |
4 |
5 | def gradient_descent():
6 | # 读取数据集
7 | df = pd.read_csv("nyc-east-river-bicycle-counts.csv", index_col=0)
8 | # 读取自变量
9 | x = df['Brooklyn Bridge'].values
10 | # 读取因变量
11 | y = df['Manhattan Bridge'].values
12 |
13 | w = 0 # 初始参数为 0
14 | b = 0 # 初始参数为 0
15 | lr = 0.000000001 # 学习率
16 | num_iter = 1000 # 迭代次数
17 | for i in range(num_iter): # 梯度下降迭代
18 | # 计算近似值
19 | y_hat = (w * x) + b
20 | # 计算参数对应梯度
21 | w_gradient = -(2/len(x)) * sum(x * (y - y_hat))
22 | b_gradient = -(2/len(x)) * sum(y - y_hat)
23 | # 根据梯度更新参数
24 | w -= lr * w_gradient
25 | b -= lr * b_gradient
26 |
27 | return w, b
28 |
--------------------------------------------------------------------------------
/Answers/week3-challenge-04/手写字符分类预测.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | " \n",
8 | "\n",
9 | "# 手写字符分类预测"
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "---"
17 | ]
18 | },
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {},
22 | "source": [
23 | "**以下内容仅保留挑战代码部分,挑战全文请到原课程查看。**"
24 | ]
25 | },
26 | {
27 | "cell_type": "markdown",
28 | "metadata": {},
29 | "source": [
30 | "---"
31 | ]
32 | },
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {},
36 | "source": [
37 | "**挑战:使用 `1x5` 的子图样式绘制 Digits 数据集前 `5` 个手写字符的图像。**"
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": null,
43 | "metadata": {},
44 | "outputs": [],
45 | "source": [
46 | "### 代码开始 ### (3~5 行代码)\n",
47 | "fig, axes = plt.subplots(1, 5, figsize=(12,4))\n",
48 | "for i, image in enumerate(digits.images[:5]):\n",
49 | " axes[i].imshow(image, cmap=plt.cm.gray_r)\n",
50 | "### 代码结束 ###"
51 | ]
52 | },
53 | {
54 | "cell_type": "markdown",
55 | "metadata": {},
56 | "source": [
57 | "---"
58 | ]
59 | },
60 | {
61 | "cell_type": "markdown",
62 | "metadata": {},
63 | "source": [
64 | "**挑战:使用 `train_test_split()` 将数据集切分为 80%(训练集) 和 20%(测试集) 两部分。**"
65 | ]
66 | },
67 | {
68 | "cell_type": "code",
69 | "execution_count": null,
70 | "metadata": {},
71 | "outputs": [],
72 | "source": [
73 | "### 代码开始 ### (≈ 2 行代码)\n",
74 | "from sklearn.model_selection import train_test_split\n",
75 | "\n",
76 | "train_x, test_x, train_y, test_y = train_test_split(digits.data, digits.target, test_size=0.2, random_state=30)\n",
77 | "### 代码结束 ###"
78 | ]
79 | },
80 | {
81 | "cell_type": "markdown",
82 | "metadata": {},
83 | "source": [
84 | "---"
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "**挑战:使用 `MLPClassifier()` 搭建神经网络结构,并训练手写字符识别模型,最后得到在测试集上的预测准确率。**"
92 | ]
93 | },
94 | {
95 | "cell_type": "code",
96 | "execution_count": null,
97 | "metadata": {},
98 | "outputs": [],
99 | "source": [
100 | "from sklearn.neural_network import MLPClassifier\n",
101 | "from sklearn.metrics import accuracy_score\n",
102 | "\n",
103 | "def mpl():\n",
104 | " \"\"\"\n",
105 | " 参数:无\n",
106 | "\n",
107 | " 返回:\n",
108 | " model -- 人工神经网络模型\n",
109 | " score -- 测试集上的预测准确率\n",
110 | " \"\"\"\n",
111 | " ### 代码开始 ### (≈ 2 行代码)\n",
112 | " model = MLPClassifier(\n",
113 | " hidden_layer_sizes=(100, 50),\n",
114 | " activation='relu',\n",
115 | " solver='sgd',\n",
116 | " learning_rate_init=0.02,\n",
117 | " learning_rate='constant',\n",
118 | " max_iter=100,\n",
119 | " random_state=1\n",
120 | " )\n",
121 | "\n",
122 | " model.fit(train_x, train_y)\n",
123 | " score = accuracy_score(test_y, model.predict(test_x))\n",
124 | " ### 代码结束 ###\n",
125 | " return model, score"
126 | ]
127 | },
128 | {
129 | "cell_type": "markdown",
130 | "metadata": {},
131 | "source": [
132 | "---"
133 | ]
134 | },
135 | {
136 | "cell_type": "markdown",
137 | "metadata": {},
138 | "source": [
139 | " "
140 | ]
141 | }
142 | ],
143 | "metadata": {
144 | "kernelspec": {
145 | "display_name": "Python 3",
146 | "language": "python",
147 | "name": "python3"
148 | },
149 | "language_info": {
150 | "codemirror_mode": {
151 | "name": "ipython",
152 | "version": 3
153 | },
154 | "file_extension": ".py",
155 | "mimetype": "text/x-python",
156 | "name": "python",
157 | "nbconvert_exporter": "python",
158 | "pygments_lexer": "ipython3",
159 | "version": "3.7.0"
160 | }
161 | },
162 | "nbformat": 4,
163 | "nbformat_minor": 2
164 | }
165 |
--------------------------------------------------------------------------------
/Answers/week3-challenge-05/使用聚类压缩图像.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | " \n",
8 | "\n",
9 | "# 使用聚类压缩图像"
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "---"
17 | ]
18 | },
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {},
22 | "source": [
23 | "**以下内容仅保留挑战代码部分,挑战全文请到原课程查看。**"
24 | ]
25 | },
26 | {
27 | "cell_type": "markdown",
28 | "metadata": {},
29 | "source": [
30 | "---"
31 | ]
32 | },
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {},
36 | "source": [
37 | "**挑战:将形状为 $(516, 819, 3)$ 的数据转换为 $(422604, 3)$ 形状的数据。**"
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": null,
43 | "metadata": {},
44 | "outputs": [],
45 | "source": [
46 | "\"\"\"数据格式变换\n",
47 | "\"\"\"\n",
48 | "### 代码开始 ###(≈ 1 行代码)\n",
49 | "data = chengdu.reshape(516 * 819, 3)\n",
50 | "### 代码结束 ###"
51 | ]
52 | },
53 | {
54 | "cell_type": "markdown",
55 | "metadata": {},
56 | "source": [
57 | "---"
58 | ]
59 | },
60 | {
61 | "cell_type": "markdown",
62 | "metadata": {},
63 | "source": [
64 | "**挑战:计算 `422604` 个像素点中种类的个数。**"
65 | ]
66 | },
67 | {
68 | "cell_type": "code",
69 | "execution_count": null,
70 | "metadata": {},
71 | "outputs": [],
72 | "source": [
73 | "\"\"\"计算像素点种类个数\n",
74 | "\"\"\"\n",
75 | "def get_variety(data):\n",
76 | " \"\"\"\n",
77 | " 参数:\n",
78 | " 预处理后像素点集合\n",
79 | "\n",
80 | " 返回:\n",
81 | " num_variety -- 像素点种类个数\n",
82 | " \"\"\"\n",
83 | "\n",
84 | " ### 代码开始 ### (≈ 3 行代码)\n",
85 | " temp=data.tolist()\n",
86 | " num_variety=len(set([tuple(t) for t in temp]))\n",
87 | " ### 代码结束 ###\n",
88 | " \n",
89 | " return num_variety"
90 | ]
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {},
95 | "source": [
96 | "---"
97 | ]
98 | },
99 | {
100 | "cell_type": "markdown",
101 | "metadata": {},
102 | "source": [
103 | "**挑战:使用 Mini Batch K-Means 聚类方法对像素点进行聚类,并用每一个中心的像素点代替属于该类别的像素点。**"
104 | ]
105 | },
106 | {
107 | "cell_type": "code",
108 | "execution_count": null,
109 | "metadata": {},
110 | "outputs": [],
111 | "source": [
112 | "from sklearn.cluster import MiniBatchKMeans\n",
113 | "\n",
114 | "### 代码开始 ###(≈ 4 行代码)\n",
115 | "model = MiniBatchKMeans(10)\n",
116 | "model.fit(data)\n",
117 | "predict=model.predict(data)\n",
118 | "### 代码结束 ###\n",
119 | "\n",
120 | "new_colors = model.cluster_centers_[predict]"
121 | ]
122 | },
123 | {
124 | "cell_type": "markdown",
125 | "metadata": {},
126 | "source": [
127 | "---"
128 | ]
129 | },
130 | {
131 | "cell_type": "markdown",
132 | "metadata": {},
133 | "source": [
134 | "**挑战:将聚类后并替换为类别中心点值的像素点,变换为数据处理前的格式,并绘制出图片进行对比展示。**"
135 | ]
136 | },
137 | {
138 | "cell_type": "code",
139 | "execution_count": null,
140 | "metadata": {},
141 | "outputs": [],
142 | "source": [
143 | "fig, ax = plt.subplots(1, 2, figsize=(16, 6))\n",
144 | "\n",
145 | "### 代码开始 ###(≈ 3 行代码)\n",
146 | "new_chengdu = new_colors.reshape(chengdu.shape)\n",
147 | "ax[0].imshow(chengdu)\n",
148 | "ax[1].imshow(new_chengdu)\n",
149 | "### 代码结束 ###"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "metadata": {},
155 | "source": [
156 | "---"
157 | ]
158 | },
159 | {
160 | "cell_type": "markdown",
161 | "metadata": {},
162 | "source": [
163 | " "
164 | ]
165 | }
166 | ],
167 | "metadata": {
168 | "kernelspec": {
169 | "display_name": "Python 3",
170 | "language": "python",
171 | "name": "python3"
172 | },
173 | "language_info": {
174 | "codemirror_mode": {
175 | "name": "ipython",
176 | "version": 3
177 | },
178 | "file_extension": ".py",
179 | "mimetype": "text/x-python",
180 | "name": "python",
181 | "nbconvert_exporter": "python",
182 | "pygments_lexer": "ipython3",
183 | "version": "3.7.0"
184 | }
185 | },
186 | "nbformat": 4,
187 | "nbformat_minor": 2
188 | }
189 |
--------------------------------------------------------------------------------
/Answers/week4-challenge-01/banknote.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | import numpy as np
3 | from sklearn.svm import SVC
4 |
5 | def identify():
6 |
7 | df_train = pd.read_csv("banknote_train.csv")
8 | df_test = pd.read_csv("banknote_test.csv")
9 |
10 | model = SVC(gamma='auto')
11 | model.fit(df_train.iloc[:, :-1], df_train['class'])
12 | df_test['class'] = model.predict(df_test)
13 |
14 | return df_test
--------------------------------------------------------------------------------
/Answers/week4-challenge-02/association.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | from mlxtend.preprocessing import TransactionEncoder
3 | from mlxtend.frequent_patterns import apriori
4 | from mlxtend.frequent_patterns import association_rules as rules
5 |
6 | def rule():
7 |
8 | df = pd.read_csv("shopping_data.csv", header=None)
9 | dataset = df.stack().groupby(level=0).apply(list).tolist()
10 |
11 | te = TransactionEncoder() # 定义模型
12 | te_ary = te.fit_transform(dataset) # 转换数据集
13 | df = pd.DataFrame(te_ary, columns=te.columns_) # 将数组处理为 DataFrame
14 |
15 | frequent_itemsets = apriori(df, min_support=0.05, use_colnames=True)
16 | association_rules = rules(frequent_itemsets, metric="confidence", min_threshold=0.2) # 置信度阈值为 0.1
17 |
18 | return frequent_itemsets, association_rules
--------------------------------------------------------------------------------
/Answers/week4-challenge-03/google_stock.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 |
4 | def quarter_volume():
5 | df = pd.read_csv("GOOGL.csv", index_col=0)
6 | df.index = pd.to_datetime(df.index)
7 | df = df.resample('Q').agg({"Open": 'mean', "High": 'mean', "Low": 'mean',
8 | "Close": 'mean', "Adj Close": 'mean', "Volume": 'sum'})
9 | df = df.sort_values(by='Volume', ascending=False)
10 | return df
--------------------------------------------------------------------------------
/Answers/week4-challenge-04/production_index.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | from statsmodels.tsa.stattools import arma_order_select_ic
3 |
4 |
5 | def arima():
6 | df = pd.read_csv("agriculture.csv", index_col=0)
7 | diff = df.diff().dropna()
8 | p, q = arma_order_select_ic(diff, ic='aic')['aic_min_order'] # AIC
9 | d = 1
10 | return p, d, q
11 |
--------------------------------------------------------------------------------
/Answers/week4-challenge-05/chengdu_pm25.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | from fbprophet import Prophet
3 |
4 |
5 | def additive():
6 | df = pd.read_csv("Chengdu_HourlyPM25.csv")
7 | df_nan = df.replace({-999: pd.np.NaN})
8 | df = df_nan.fillna(method='ffill').fillna(method='bfill')
9 |
10 | df.index = pd.to_datetime(df['Date (LST)'])
11 | df = df.resample('D').mean()
12 | df = df.reset_index()
13 | df.rename(columns={'Date (LST)': 'ds', 'Value': 'y'}, inplace=True)
14 |
15 | m = Prophet() # 创建加法模型
16 | m.fit(df)
17 |
18 | future = m.make_future_dataframe(periods=365, freq='D') # 生成预测序列
19 | forecast = m.predict(future) # 预测
20 | # 仅保留预测值和相应的置信区间
21 | forecast = forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']]
22 | forecast = forecast.set_index('ds')['2017-01-01':]
23 |
24 | forecast.to_csv("forecast.csv") # 存为数据文件
25 |
26 | return forecast
27 |
28 | additive()
--------------------------------------------------------------------------------
/Answers/week5-spiders-01/lianjia_spider.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from bs4 import BeautifulSoup
3 | import time
4 | from tqdm import tqdm
5 | import re
6 | import sqlite3
7 | import pandas as pd
8 |
9 | '''
10 | 爬虫代码分为三步:
11 | 1. 爬取房屋 id
12 | 2. 根据房屋 id 组合 url,然后依次爬取房屋的具体界面获取信息
13 | 3. 保存到本地
14 | '''
15 |
16 | base_url = 'https://sh.lianjia.com/zufang/'
17 | test_url = 'https://sh.lianjia.com/zufang/pg1/'
18 | headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'}
19 |
20 | # 获取一页的房屋列表,具体为房屋的 id,例如 107100610451
21 | def getHouseURLList(page_url):
22 | try:
23 | r = requests.get(page_url, timeout=5, headers=headers)
24 | if r.status_code==403:
25 | print('访问被拒,请稍后再试')
26 | except requests.exceptions.Timeout:
27 | # 请求超时,返回无效数据
28 | return None
29 | content = r.content
30 | soup = BeautifulSoup(content)
31 | result_list = list(soup.select('#house-lst')[0].children)
32 | return_list = []
33 | for result in result_list:
34 | return_list.append(result['data-id'])
35 | return return_list
36 |
37 | # 示例
38 | # return_list = getHouseURLList(test_url)
39 |
40 | # 房屋 id
41 | data_id_list = []
42 |
43 | # 多走几轮,以获得更全的数据
44 | for _ in range(1):
45 | # for i in tqdm(range(1, 101)):
46 | for i in tqdm(range(1, 2)):
47 | page_url = base_url+'pg{}/'.format(i)
48 | return_list = getHouseURLList(page_url)
49 | if not return_list:
50 | time.sleep(10)
51 | continue
52 | data_id_list.extend(return_list)
53 |
54 | # 去除重复数据
55 | data_id_list = list(set(data_id_list))
56 |
57 | # 写入本地文件,保存房屋 id
58 | with open('house_id_list.txt', 'w') as f:
59 | f.write('\n'.join(data_id_list))
60 |
61 |
62 | # 清理面积
63 | def clean_str(s):
64 | # 去除中文
65 | re.sub(r'[^\x00-\x7f]', '', s)
66 | new_s = []
67 | for c in s:
68 | # 遇到非数字则舍去
69 | if c.isdigit(): new_s.append(c)
70 | else: break
71 | return ''.join(new_s)
72 |
73 | # 定义一个类保存数据
74 | class Room(object):
75 | def __init__(self, url):
76 | self.done = False
77 | self.area = 0
78 | self.url = url
79 | self.price = ''
80 | self.isRemoved = ''
81 | self.special_label = ''
82 | self.title = ''
83 | self.floor = ''
84 | self.is_near_subway = ''
85 | self.publish_time = ''
86 | self.rooms = ''
87 | self.toilet = ''
88 | self.halls = ''
89 | self.rent_way = ''
90 | self.location = ''
91 |
92 | # 房屋面积
93 | def setArea(self, area):
94 | self.area = float(clean_str(area))
95 |
96 | # 价格
97 | def setPrice(self, price):
98 | self.price = price
99 |
100 | # 是否下架
101 | def setIsRemoved(self, isRemoved):
102 | self.isRemoved = isRemoved
103 |
104 | # 是否精装修
105 | def setSpecialLabel(self, special_label):
106 | self.special_label = special_label
107 |
108 | # 户型: 房间数量,房间,大厅,卫生间; 出租方式: 整租、合租
109 | def setType(self, type):
110 | tmp = type.split()
111 | if len(tmp) == 1:
112 | room_count = tmp[0]
113 | rent_way = '暂无信息'
114 | else:
115 | room_count, rent_way = tmp
116 | room_count = re.sub(r'[^\x00-\x7f]', ' ', room_count).strip().split()
117 | room_count = list(map(int, room_count))
118 |
119 | # 部分房屋无卫生间或客厅
120 | if len(room_count) < 3:
121 | for i in range(3 - len(room_count)):
122 | room_count.append(0)
123 |
124 | self.rooms = room_count[0]
125 | self.halls = room_count[1]
126 | self.toilet = room_count[2]
127 | self.rent_way = rent_way
128 |
129 | # 位置
130 | def setLocation(self, location):
131 | self.location = location
132 |
133 | # 是否靠近地铁
134 | def setSubway(self, is_near_subway):
135 | self.is_near_subway = is_near_subway
136 |
137 | # 朝向
138 | def setDirection(self, direction):
139 | self.direction = direction
140 |
141 | # 楼层
142 | def setFloor(self, floor):
143 | self.floor = floor
144 |
145 | # 发布时间
146 | def setPublishTime(self, publish_time):
147 | self.publish_time = publish_time
148 |
149 | # 房屋标题
150 | def setTitle(self, title):
151 | self.title = title
152 |
153 | # 房屋链接
154 | def setURL(self, URL):
155 | self.url = URL
156 |
157 | # 是否爬取成功
158 | def setDone(self, done):
159 | self.done = done
160 |
161 | def __repr__(self):
162 | return str(self.__dict__)
163 |
164 | # 给定 url 获取房屋信息
165 | def getRoom(url):
166 | room = Room(url)
167 | try:
168 | r = requests.get(url, timeout=5, headers=headers)
169 | if r.status_code==403:
170 | print('访问被拒,请稍后再试')
171 | except requests.exceptions.Timeout:
172 | time.sleep(2)
173 | print('timeout')
174 | return Room('invalid')
175 | content = r.content.decode()
176 |
177 | soup = BeautifulSoup(content, features='lxml')
178 |
179 | title = soup.find('h1', class_='main').text
180 | room.setTitle(title)
181 |
182 | price_div = soup.find('div', class_='price')
183 | price_list = list(price_div.stripped_strings) # ['9000', '元/月', '精装修']
184 | price = ''.join(price_list[:2])
185 | room.setPrice(price)
186 |
187 | special_label = ' '.join(price_list[2:]) if len(price_list)>2 else '无'
188 | room.setSpecialLabel(special_label)
189 | isRemoved = '已下架' if price_div['class'][1] == 'isRemove' else '正在出租'
190 | room.setIsRemoved(isRemoved)
191 |
192 | room_info = soup.find('div', class_='zf-room')
193 | room_info_list = list(room_info.stripped_strings)
194 |
195 | location = "{} {} {}".format(room_info_list[15], room_info_list[16], room_info_list[11])
196 | room.setLocation(location)
197 | room.setPublishTime(room_info_list[-1])
198 | room.setArea(room_info_list[1])
199 | room.setType(room_info_list[3]) # 4室2厅3卫;
200 | room.setFloor(room_info_list[5])
201 | room.setDirection(room_info_list[7])
202 | room.setSubway(room_info_list[9])
203 |
204 | room.setDone(True)
205 |
206 | return room
207 |
208 | # 连接数据库
209 | conn = sqlite3.connect('lianjia.db')
210 |
211 | cursor = conn.cursor()
212 | # 创建表,如果已创建,则删除下面这行
213 | cursor.execute('''
214 | CREATE TABLE ROOM(
215 | url VARCHAR(1000) PRIMARY KEY,
216 | price Double,
217 | area Double,
218 | isRemoved VARCHAR(1000),
219 | special_label VARCHAR(1000),
220 | rooms INT,
221 | halls INT,
222 | toilet INT,
223 | rent_way INT,
224 | location VARCHAR(1000),
225 | is_near_subway VARCHAR(1000),
226 | direction VARCHAR(1000),
227 | floor VARCHAR(1000),
228 | publish_time VARCHAR(1000),
229 | title VARCHAR(1000)
230 | )
231 | ''')
232 |
233 | SELECT_COMMAND = "select * from ROOM where url='{}';"
234 | INSERT_COMMAND = "insert into ROOM(url, price, area, isRemoved, \
235 | special_label, rooms, halls, toilet, rent_way, \
236 | location, is_near_subway, direction, floor, publish_time, title) \
237 | values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
238 |
239 | # 根据上面爬取到的房屋 ID 组合生成 url,然后依次爬取
240 | def getAllHouseInfo(file_path):
241 | base_url = 'https://sh.lianjia.com/zufang/{}.html'
242 | with open(file_path) as f:
243 | lines = f.readlines()
244 |
245 | urls = [base_url.format(line.strip('\n')) for line in lines]
246 | for url in tqdm(urls):
247 | cursor = conn.cursor()
248 | cursor.execute(SELECT_COMMAND.format(url))
249 | if len(cursor.fetchall()) != 0:
250 | continue
251 | cursor.close()
252 | # 如果失败,最多尝试 5 次
253 | count = 0
254 | while count < 5:
255 | room = getRoom(url)
256 | if room.done:
257 | break
258 | count += 1
259 | if count == 5:
260 | continue
261 |
262 | # 插入数据库
263 | cursor = conn.cursor()
264 | cursor.execute(INSERT_COMMAND,
265 | (room.url, room.price, room.area, room.isRemoved, room.special_label,
266 | room.rooms, room.halls, room.toilet, room.rent_way, room.location, room.is_near_subway,
267 | room.direction, room.floor, room.publish_time, room.title))
268 | cursor.close()
269 | conn.commit()
270 | if cursor.rowcount != 1:
271 | print('插入错误')
272 |
273 |
274 | getAllHouseInfo('house_id_list.txt')
275 |
276 | csv_path = 'lianjia.csv'
277 |
278 | cursor = conn.cursor()
279 |
280 | # 保存到本地 csv 文件
281 | cursor.execute('SELECT * FROM ROOM')
282 |
283 | data = cursor.fetchall()
284 | data = list(map(list, data))
285 | name_attribute = ['url', 'price', 'area', 'state', 'label', 'rooms', 'halls', 'toilets', 'rentway', 'location',
286 | 'subway', 'direction', 'floor', 'publishtime', 'title']
287 | data_frame =pd.DataFrame(columns=name_attribute,data=data)
288 | data_frame.to_csv(csv_path, encoding='utf_8_sig')
289 | conn.close()
--------------------------------------------------------------------------------
/Answers/week5-spiders-02/create_sqlite_database.py:
--------------------------------------------------------------------------------
1 | import sqlite3
2 |
3 |
4 | # 创建携程数据库
5 | conn = sqlite3.connect('xiecheng.db')
6 |
7 | # 创建一个包含机票信息的表
8 | # 分别是 公司名、出发时间、到达时间、出发机场、到达机场、飞机类型、准点率、飞机编号、价格、日期
9 | CREATE_COMMAND1 = '''
10 | CREATE table AIRPLANE (
11 | company_name varchar(1000),
12 | start_time varchar(1000),
13 | arrival_time varchar(1000),
14 | start_airport varchar(1000),
15 | arrival_airport varchar(1000),
16 | airpane_type varchar(1000),
17 | ontime_rate float,
18 | airpane_number varchar(1000),
19 | price float,
20 | date varchar(1000)
21 | );
22 | '''
23 |
24 | # 选择预计,根据飞机编号、日期、出发时间选出需要的机票信息
25 | SELECT_COMMAND = '''
26 | select * from AIRPLANE where airpane_number=? and date=? and start_time=?;
27 | '''
28 |
29 | # 插入新的数据
30 | INSERT_COMMAND1 = '''
31 | insert into AIRPLANE values(?,?,?,?,?,?,?,?,?,?);
32 | '''
33 |
34 | # 创建一个最低价格的表,包含出发城市、到达城市、日期、最低价格
35 | CREATE_COMMAND2 = '''
36 | CREATE table LOWEST_PRICE (
37 | start_city varchar(1000),
38 | arrival_city varchar(1000),
39 | date varchar(1000),
40 | price float
41 | );
42 | '''
43 |
44 | # 插入数据
45 | INSERT_COMMAND2 = '''
46 | insert into LOWEST_PRICE values(?,?,?,?);
47 | '''
48 |
49 | # 创建表
50 | cursor = conn.cursor()
51 | cursor.execute(CREATE_COMMAND1)
52 | cursor.close()
53 | cursor = conn.cursor()
54 | cursor.execute(CREATE_COMMAND2)
55 | cursor.close()
56 |
--------------------------------------------------------------------------------
/Answers/week5-spiders-02/insert_database.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import pandas as pd
3 |
4 |
5 | base = datetime.date(2018, 10, 30)
6 | numdays = 80
7 |
8 | # 所有的十月三十号以后的八十天的 list
9 | date_list = [base + datetime.timedelta(days=x) for x in range(0, numdays)]
10 |
11 | # 获取从 start 到 dest 的数据并插入数据库中
12 | def getTickets(start, dest, driver, date_list, conn):
13 | cursor = conn.cursor()
14 | name_attribute = []
15 | for one_day in tqdm_notebook(date_list):
16 | # 获取数据
17 | tmp = get_ticket_info(start, dest, str(one_day), driver)
18 | for x in tmp:
19 | result = cursor.execute(
20 | SELECT_COMMAND, (x[-2], str(one_day), x[1])).fetchall()
21 | x.append(str(one_day))
22 | if len(result) == 0:
23 | # 如果没有爬取则插入数据库
24 | cursor.execute(INSERT_COMMAND1, x)
25 | conn.commit()
26 | cursor.close()
27 |
28 |
29 | # 成都到上海和上海到成都
30 | getTickets('CTU', 'SHA', driver, date_list, conn)
31 | getTickets('SHA', 'CTU', driver, date_list, conn)
32 |
--------------------------------------------------------------------------------
/Answers/week5-spiders-02/xiecheng_spider.py:
--------------------------------------------------------------------------------
1 | # 使用 BeautifulSoup 进行解析
2 | from bs4 import BeautifulSoup
3 | from selenium import webdriver
4 | from selenium.common.exceptions import TimeoutException
5 | import time
6 | from selenium.webdriver.chrome.options import Options
7 | import re
8 | from selenium.webdriver.common.proxy import Proxy, ProxyType
9 |
10 |
11 | '''
12 | dstation: 出发城市代码
13 | astation: 到达城市代码
14 | date: 出发日期,形如 2018-10-30
15 | driver: 创建的 webdriver
16 | '''
17 | def get_ticket_info(dstation, astation, date, driver):
18 | url = "http://flights.ctrip.com/booking/%s-%s-day-1.html?DDate1=%s" % (
19 | dstation, astation, date)
20 | # 一直尝试到成功
21 | while True:
22 | try:
23 | driver.get(url)
24 | break
25 | except TimeoutException as e:
26 | pass
27 | # 等待页面加载出来
28 | time.sleep(2)
29 |
30 | # webdriver 执行 js 语句滑动窗口,一直滑动到底部
31 | initial_pagesource = driver.page_source
32 | while True:
33 | # 滑到页面底部,暂停 0.1 秒是为了等待页面刷新出结果
34 | driver.execute_script(
35 | "window.scrollTo(0, document.body.scrollHeight);")
36 | # 等待数据加载
37 | time.sleep(1)
38 | # 如果当前页面和上一个页面的 html 内容不同,则表明滑动到底部了
39 | if initial_pagesource == driver.page_source:
40 | break
41 | initial_pagesource = driver.page_source
42 |
43 | # 使用 BeautifulSoup 解析 html 内容
44 | soup = BeautifulSoup(initial_pagesource)
45 | # 获取搜索结果的每一个项
46 | result = soup.find_all("div", class_=["search_table_header", ])
47 | result_list = []
48 | for ticket_info in result:
49 | try:
50 | # 航空公司名、出发时间、到达时间
51 | company_name, start_time, arrival_time = [
52 | x.text for x in ticket_info.find_all('strong')]
53 | # 出发机场、到达机场
54 | start_airport, arrival_airport = [
55 | x.text for x in ticket_info.find_all("div", class_=["airport", ])]
56 | tmp = [x.text for x in ticket_info.find_all(
57 | "span", class_=["direction_black_border", ])]
58 | # 飞机类型,准点率(可能没有)
59 | if len(tmp) == 2:
60 | airpane_type, ontime_rate = tmp
61 | ontime_rate = float(''.join(filter(str.isdigit, ontime_rate)))/100
62 | else:
63 | airpane_type = tmp[0]
64 | ontime_rate = 0
65 | # 航班编号
66 | airpane_number = [x.text for x in ticket_info.find_all("span")][2]
67 | # 价格(经济舱)
68 | price = int([''.join(list(filter(str.isdigit, x.text)))
69 | for x in ticket_info.find_all("span", class_=["base_price02", ])][0])
70 | result_list.append([company_name, start_time, arrival_time, start_airport,
71 | arrival_airport, airpane_type, ontime_rate, airpane_number, price])
72 |
73 | except Exception as E:
74 | print(E)
75 |
76 | # 按机票价格排序后返回
77 | return sorted(result_list, key=lambda x: x[-1])
78 |
79 | if __name__ == "__main__":
80 | # driver = webdriver.PhantomJS(executable_path="./chromedriver", service_args=['--load-images=no'])
81 | options = Options()
82 | # options = webdriver.ChromeOptions()
83 | # options.add_argument("--headless") # Runs Chrome in headless mode.
84 | options.add_argument('--no-sandbox') # # Bypass OS security model
85 | options.add_argument('start-maximized')
86 | options.add_argument('disable-infobars')
87 | options.add_argument("--disable-extensions")
88 | driver = webdriver.Chrome(options=options, executable_path='./chromedriver')
89 | # driver = webdriver.Chrome("./chromedriver")
90 | result_list = get_ticket_info('CTU', 'SHA', '2018-10-30', driver)
91 | print(result_list)
--------------------------------------------------------------------------------
/Assignments/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
实验楼《楼+ 数据分析与挖掘实战》优秀项目挑战报告|课程报名
4 |
5 |
6 |
7 |
8 | 如果 Github 加载缓慢,可以点击下方链接快速浏览。👇
9 |
10 | ### 第 1 期课程
11 |
12 | - 报告题目:[中国保险业过去五年基础数据分析](https://nbviewer.jupyter.org/github/shiyanlou/louplus-dm/blob/master/Assignments/%F0%9F%8F%85%EF%B8%8Fdm01-stenphen-%E4%B8%AD%E5%9B%BD%E4%BF%9D%E9%99%A9%E4%B8%9A%E8%BF%87%E5%8E%BB%E4%BA%94%E5%B9%B4%E5%9F%BA%E7%A1%80%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90.ipynb)|学员昵称:stenphen 🌟
13 | - 报告题目:[上海历史天气数据分析预测](https://nbviewer.jupyter.org/github/shiyanlou/louplus-dm/blob/master/Assignments/%F0%9F%8F%85%EF%B8%8Fdm01-stenphen-%E4%B8%AD%E5%9B%BD%E4%BF%9D%E9%99%A9%E4%B8%9A%E8%BF%87%E5%8E%BB%E4%BA%94%E5%B9%B4%E5%9F%BA%E7%A1%80%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90.ipynb)|学员昵称:BellaG
14 | - 报告题目:[双色球历史数据统计预测](https://nbviewer.jupyter.org/github/shiyanlou/louplus-dm/blob/master/Assignments/%F0%9F%A5%89dm01-hcccom-%E5%8F%8C%E8%89%B2%E7%90%83%E5%8E%86%E5%8F%B2%E6%95%B0%E6%8D%AE%E7%BB%9F%E8%AE%A1%E9%A2%84%E6%B5%8B.ipynb)|学员昵称:hcccom
15 |
16 | ### 第 2 期课程
17 |
18 | - 报告题目:[杭州互联网寒冬背景下的数据分析岗现状分析](https://nbviewer.jupyter.org/github/shiyanlou/louplus-dm/blob/master/Assignments/%F0%9F%8F%85%EF%B8%8Fdm02-%E7%B1%B3%E7%AB%B9314159-%E6%9D%AD%E5%B7%9E%E4%BA%92%E8%81%94%E7%BD%91%E5%AF%92%E5%86%AC%E8%83%8C%E6%99%AF%E4%B8%8B%E7%9A%84%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E5%B2%97%E7%8E%B0%E7%8A%B6%E5%88%86%E6%9E%90.ipynb)|学员昵称:米竹314159 🌟
19 | - 报告题目:[医学专业论坛的数据爬取和分析](https://nbviewer.jupyter.org/github/shiyanlou/louplus-dm/blob/master/Assignments/%F0%9F%A5%88dm02-linnecn-%E5%8C%BB%E5%AD%A6%E4%B8%93%E4%B8%9A%E8%AE%BA%E5%9D%9B%E7%9A%84%E6%95%B0%E6%8D%AE%E7%88%AC%E5%8F%96%E5%92%8C%E5%88%86%E6%9E%90.ipynb)|学员昵称:linnecn
20 |
21 | ### 第 3 期课程
22 |
23 | - 虚位以待
24 |
25 | ### 第 4 期课程
26 |
27 | - 报告题目:[链家成都市区挂牌二手房分析](https://nbviewer.jupyter.org/github/shiyanlou/louplus-dm/blob/master/Assignments/%F0%9F%8F%85%EF%B8%8Fdm04-Luo2019-%E9%93%BE%E5%AE%B6%E6%88%90%E9%83%BD%E5%B8%82%E5%8C%BA%E6%8C%82%E7%89%8C%E4%BA%8C%E6%89%8B%E6%88%BF%E5%88%86%E6%9E%90.ipynb)|学员昵称:Luo2019 🌟
28 | - 报告题目:[B 站番剧数据简单分析](https://nbviewer.jupyter.org/github/shiyanlou/louplus-dm/blob/master/Assignments/%F0%9F%A5%88dm04-Yueyec-B-%E7%AB%99%E7%95%AA%E5%89%A7%E6%95%B0%E6%8D%AE%E7%AE%80%E5%8D%95%E5%88%86%E6%9E%90.ipynb)|学员昵称:Yueyec
29 |
30 | ### 第 5 期课程
31 |
32 | - 报告题目:[京东手机销售数据分析](https://www.kaggle.com/ted0001/dm05-998494)|学员昵称:[Ted_Wei](https://www.lanqiao.cn/users/998494/) 🌟
33 | - 报告题目:[通信基站室内分布系统外引小区识别](https://www.kaggle.com/cym1085893/dm05-1085893)|学员昵称:[yiming_chen](https://www.lanqiao.cn/users/1085893/)
34 |
35 | ### 第 6 期课程
36 |
37 | - 报告题目:[大连地区酒店数据分析](https://www.kaggle.com/louplus/dm06-937174)|学员昵称:[Miss_candy](https://www.lanqiao.cn/users/937174/) 🌟
38 |
39 | ### 第 7 期课程
40 |
41 | - 报告题目:[微博搜索“双十一”数据分析](https://www.kaggle.com/lanjie/dm07-1127847)|学员昵称:[灵汐](https://www.lanqiao.cn/users/1127847/)
42 |
43 | ### 第 8 期课程
44 |
45 | - 报告题目:[B站up主“老番茄”基本数据采集分析](https://www.kaggle.com/truwbin/dm08-877339-b-up)|学员昵称:[今天小古不出门](https://www.lanqiao.cn/users/877339/) 🌟
46 | - 报告题目:[下厨房家常菜菜谱分析及新菜谱预测评分](https://www.kaggle.com/fors3c/dm08-ns3c)|学员昵称:ns3c
47 |
48 | ### 第 9 期课程
49 |
50 | - 报告题目:[世界银行国际旅游业指标分析](https://www.kaggle.com/furongrong/dm09-535211)|学员昵称:[RR25](https://www.lanqiao.cn/users/535211/) 🌟
51 | - 报告题目:[猪肉价格数据分析](https://www.kaggle.com/suxiaomo/dm09-1180757)|学员昵称:[苏小墨](https://www.lanqiao.cn/users/1180757/)
52 | - 报告题目:[汽车之家数据分析](https://www.kaggle.com/mengchenshang/dm09-1176812)|学员昵称:[凹润纸](https://www.lanqiao.cn/users/1176812/)
53 |
54 | ### 第 10 期课程
55 |
56 | - 虚位以待
57 |
58 | ### 第 11 期课程
59 |
60 | - 报告题目:[科比职业生涯回顾与模型预测](https://www.kaggle.com/yemujianglin/dm11-1276351)|学员昵称:[夜幕降临_](https://www.lanqiao.cn/users/1276351/) 🌟
61 |
62 | ### 第 12 期课程
63 |
64 | - 虚位以待
65 |
66 |
67 | ### 第 13 期课程
68 |
69 | - 报告题目:[基于 Python 语言的加拿大联邦大选数据分析](https://www.kaggle.com/czz1403/dm13-1204880-python)|学员昵称:[TXZXTLD](https://www.lanqiao.cn/users/1204880/) 🌟
70 | - 报告题目:[新冠疫情社会影响数据分析](https://www.kaggle.com/vincentbao/dm13-812273)|学员昵称:[vincentbao](https://www.lanqiao.cn/users/812273/) 🌟 已经制作成课程:https://www.lanqiao.cn/courses/2791
71 |
72 |
73 | ```
74 | - 原作者可以提 PR 更新自己的报告内容。
75 | - 实验报告版权归属原学员且授权实验楼独家使用,请勿用于商业用途。
76 | ```
77 |
--------------------------------------------------------------------------------
/Assignments/🥉dm01-hcccom-双色球历史数据统计预测.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# 双色球历史数据统计预测"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "---"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "- 报告题目:双色球历史数据统计预测\n",
22 | "- 学员昵称:hcccom\n",
23 | "- 课程期数:第一期"
24 | ]
25 | },
26 | {
27 | "cell_type": "markdown",
28 | "metadata": {},
29 | "source": [
30 | "© 本文著作权归作者所有,并授权实验楼独家使用,未经实验楼许可,不得转载使用。"
31 | ]
32 | },
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {},
36 | "source": [
37 | "---"
38 | ]
39 | },
40 | {
41 | "cell_type": "markdown",
42 | "metadata": {},
43 | "source": [
44 | "### 获取数据"
45 | ]
46 | },
47 | {
48 | "cell_type": "code",
49 | "execution_count": null,
50 | "metadata": {},
51 | "outputs": [],
52 | "source": [
53 | "import random\n",
54 | "import numpy as np\n",
55 | "import requests\n",
56 | "import csv\n",
57 | "from bs4 import BeautifulSoup\n",
58 | "headers = {\n",
59 | " 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'}\n",
60 | "res = requests.get(\n",
61 | " 'https://datachart.500.com/ssq/history/newinc/history.php?start=03001&end=18147', headers=headers) # 从03年第一期开始\n",
62 | "res.encoding = 'uft-8'\n",
63 | "soup = BeautifulSoup(res.text, 'lxml')\n",
64 | "data = soup.find_all(attrs={'class': 't_tr1'})\n",
65 | "csvFile = open(\"./ssq004.csv\", 'wt', newline='', encoding='utf-8')"
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": null,
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "def gens(x): # 模拟\n",
75 | " random.seed(x)\n",
76 | " a = np.arange(1, 34, 1).tolist()\n",
77 | " red = sorted(random.sample(a, 6))\n",
78 | " b = np.arange(1, 17, 1).tolist()\n",
79 | " blue = random.sample(b, 1)\n",
80 | " red.extend(blue)\n",
81 | " return red"
82 | ]
83 | },
84 | {
85 | "cell_type": "code",
86 | "execution_count": 8,
87 | "metadata": {},
88 | "outputs": [],
89 | "source": [
90 | "with open(r\"ssq004.csv\", 'a', newline='') as f:\n",
91 | " writer = csv.writer(f)\n",
92 | " writer.writerow([\"period\", \"real\", \"date\", \"vis\", 'r1',\n",
93 | " 'r2', 'r3', 'r4', 'r5', 'r6', 'b1']) # 先写入列名\n",
94 | " for i in range(0, len(data)):\n",
95 | " period = data[i].find_all('td')[0].text\n",
96 | " real = [int(data[i].find_all('td')[1].text), int(data[i].find_all('td')[2].text), int(data[i].find_all('td')[3].text), int(data[i].find_all(\n",
97 | " 'td')[4].text), int(data[i].find_all('td')[5].text), int(data[i].find_all('td')[6].text), int(data[i].find_all('td')[7].text)]\n",
98 | " date = data[i].find_all('td')[15].text\n",
99 | " vis = gens(date)\n",
100 | " r1 = int(data[i].find_all('td')[1].text)\n",
101 | " r2 = int(data[i].find_all('td')[2].text)\n",
102 | " r3 = int(data[i].find_all('td')[3].text)\n",
103 | " r4 = int(data[i].find_all('td')[4].text)\n",
104 | " r5 = int(data[i].find_all('td')[5].text)\n",
105 | " r6 = int(data[i].find_all('td')[6].text)\n",
106 | " b1 = int(data[i].find_all('td')[7].text)\n",
107 | "\n",
108 | " writer.writerows(\n",
109 | " [[period, real, date, vis, r1, r2, r3, r4, r5, r6, b1]])\n",
110 | "csvFile.close()"
111 | ]
112 | },
113 | {
114 | "cell_type": "markdown",
115 | "metadata": {},
116 | "source": [
117 | "### 数据处理"
118 | ]
119 | },
120 | {
121 | "cell_type": "code",
122 | "execution_count": 9,
123 | "metadata": {},
124 | "outputs": [
125 | {
126 | "data": {
127 | "text/plain": [
128 | "[3, 6, 8, 23, 25, 33, 4]"
129 | ]
130 | },
131 | "execution_count": 9,
132 | "metadata": {},
133 | "output_type": "execute_result"
134 | }
135 | ],
136 | "source": [
137 | "import pandas as pd\n",
138 | "import matplotlib.pyplot as plt\n",
139 | "df = pd.read_csv('ssq004.csv', encoding='gbk')\n",
140 | "df.set_index(\"date\", inplace=True)\n",
141 | "df.index = pd.DatetimeIndex(df.index)\n",
142 | "df.sort_index(ascending=True, inplace=True)\n",
143 | "\n",
144 | "\n",
145 | "def get_real(i):\n",
146 | " a = df.real[i]\n",
147 | " lista = a.strip('[]').split(',')\n",
148 | " map(int, lista)\n",
149 | " list_real = [int(x) for x in lista]\n",
150 | " return list_real\n",
151 | "\n",
152 | "\n",
153 | "def get_vis(i): # 产生和时间相关的随机双色球\n",
154 | " b = df.vis[i]\n",
155 | " listb = b.strip('[]').split(',')\n",
156 | " map(int, listb)\n",
157 | " list_vis = [int(x) for x in listb]\n",
158 | " return list_vis\n",
159 | "\n",
160 | "\n",
161 | "get_vis(1)"
162 | ]
163 | },
164 | {
165 | "cell_type": "code",
166 | "execution_count": null,
167 | "metadata": {},
168 | "outputs": [],
169 | "source": [
170 | "# 计算每个球出现的频率"
171 | ]
172 | },
173 | {
174 | "cell_type": "code",
175 | "execution_count": 10,
176 | "metadata": {
177 | "scrolled": true
178 | },
179 | "outputs": [],
180 | "source": [
181 | "df1 = df.drop(columns=['period', 'real', 'vis'])\n",
182 | "df2 = df1.drop(columns=['b1'])\n",
183 | "df3 = df1[['b1']]\n",
184 | "dup = df1[df1.duplicated()].count()\n",
185 | "rd1 = df2.stack().value_counts()\n",
186 | "bd1 = df3['b1'].value_counts()"
187 | ]
188 | },
189 | {
190 | "cell_type": "code",
191 | "execution_count": 11,
192 | "metadata": {
193 | "scrolled": false
194 | },
195 | "outputs": [
196 | {
197 | "data": {
198 | "image/png": "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\n",
199 | "text/plain": [
200 | ""
201 | ]
202 | },
203 | "metadata": {
204 | "needs_background": "light"
205 | },
206 | "output_type": "display_data"
207 | },
208 | {
209 | "data": {
210 | "image/png": "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\n",
211 | "text/plain": [
212 | ""
213 | ]
214 | },
215 | "metadata": {
216 | "needs_background": "light"
217 | },
218 | "output_type": "display_data"
219 | }
220 | ],
221 | "source": [
222 | "import matplotlib.pyplot as plt\n",
223 | "from pylab import *\n",
224 | "plt.figure(111)\n",
225 | "rd1.plot(kind='bar', align='center')\n",
226 | "plt.xlabel(\"red\")\n",
227 | "plt.ylabel(\"Times\")\n",
228 | "plt.show()\n",
229 | "plt.figure(112)\n",
230 | "bd1.plot(kind='bar')\n",
231 | "plt.xlabel(\"blue\")\n",
232 | "plt.ylabel(\"Times\")\n",
233 | "plt.show()"
234 | ]
235 | },
236 | {
237 | "cell_type": "markdown",
238 | "metadata": {},
239 | "source": [
240 | "### 取一组\n",
241 | " "
242 | ]
243 | },
244 | {
245 | "cell_type": "code",
246 | "execution_count": 14,
247 | "metadata": {},
248 | "outputs": [
249 | {
250 | "data": {
251 | "text/html": [
252 | "\n",
253 | "\n",
266 | "
\n",
267 | " \n",
268 | " \n",
269 | " \n",
270 | " period \n",
271 | " real \n",
272 | " vis \n",
273 | " r1 \n",
274 | " r2 \n",
275 | " r3 \n",
276 | " r4 \n",
277 | " r5 \n",
278 | " r6 \n",
279 | " b1 \n",
280 | " \n",
281 | " \n",
282 | " date \n",
283 | " \n",
284 | " \n",
285 | " \n",
286 | " \n",
287 | " \n",
288 | " \n",
289 | " \n",
290 | " \n",
291 | " \n",
292 | " \n",
293 | " \n",
294 | " \n",
295 | " \n",
296 | " \n",
297 | " 2018-12-04 \n",
298 | " 18142 \n",
299 | " [5, 8, 10, 11, 27, 28, 11] \n",
300 | " [11, 13, 16, 24, 29, 31, 8] \n",
301 | " 5 \n",
302 | " 8 \n",
303 | " 10 \n",
304 | " 11 \n",
305 | " 27 \n",
306 | " 28 \n",
307 | " 11 \n",
308 | " \n",
309 | " \n",
310 | " 2018-12-06 \n",
311 | " 18143 \n",
312 | " [4, 6, 15, 28, 32, 33, 14] \n",
313 | " [10, 14, 15, 16, 24, 33, 14] \n",
314 | " 4 \n",
315 | " 6 \n",
316 | " 15 \n",
317 | " 28 \n",
318 | " 32 \n",
319 | " 33 \n",
320 | " 14 \n",
321 | " \n",
322 | " \n",
323 | " 2018-12-09 \n",
324 | " 18144 \n",
325 | " [8, 13, 17, 18, 20, 27, 13] \n",
326 | " [3, 7, 13, 17, 19, 30, 13] \n",
327 | " 8 \n",
328 | " 13 \n",
329 | " 17 \n",
330 | " 18 \n",
331 | " 20 \n",
332 | " 27 \n",
333 | " 13 \n",
334 | " \n",
335 | " \n",
336 | " 2018-12-11 \n",
337 | " 18145 \n",
338 | " [3, 9, 13, 22, 23, 25, 6] \n",
339 | " [3, 6, 10, 12, 19, 25, 12] \n",
340 | " 3 \n",
341 | " 9 \n",
342 | " 13 \n",
343 | " 22 \n",
344 | " 23 \n",
345 | " 25 \n",
346 | " 6 \n",
347 | " \n",
348 | " \n",
349 | " 2018-12-13 \n",
350 | " 18146 \n",
351 | " [2, 10, 11, 17, 18, 29, 16] \n",
352 | " [6, 10, 21, 24, 26, 32, 3] \n",
353 | " 2 \n",
354 | " 10 \n",
355 | " 11 \n",
356 | " 17 \n",
357 | " 18 \n",
358 | " 29 \n",
359 | " 16 \n",
360 | " \n",
361 | " \n",
362 | "
\n",
363 | "
"
364 | ],
365 | "text/plain": [
366 | " period real vis \\\n",
367 | "date \n",
368 | "2018-12-04 18142 [5, 8, 10, 11, 27, 28, 11] [11, 13, 16, 24, 29, 31, 8] \n",
369 | "2018-12-06 18143 [4, 6, 15, 28, 32, 33, 14] [10, 14, 15, 16, 24, 33, 14] \n",
370 | "2018-12-09 18144 [8, 13, 17, 18, 20, 27, 13] [3, 7, 13, 17, 19, 30, 13] \n",
371 | "2018-12-11 18145 [3, 9, 13, 22, 23, 25, 6] [3, 6, 10, 12, 19, 25, 12] \n",
372 | "2018-12-13 18146 [2, 10, 11, 17, 18, 29, 16] [6, 10, 21, 24, 26, 32, 3] \n",
373 | "\n",
374 | " r1 r2 r3 r4 r5 r6 b1 \n",
375 | "date \n",
376 | "2018-12-04 5 8 10 11 27 28 11 \n",
377 | "2018-12-06 4 6 15 28 32 33 14 \n",
378 | "2018-12-09 8 13 17 18 20 27 13 \n",
379 | "2018-12-11 3 9 13 22 23 25 6 \n",
380 | "2018-12-13 2 10 11 17 18 29 16 "
381 | ]
382 | },
383 | "execution_count": 14,
384 | "metadata": {},
385 | "output_type": "execute_result"
386 | }
387 | ],
388 | "source": [
389 | "df.tail(5)"
390 | ]
391 | },
392 | {
393 | "cell_type": "code",
394 | "execution_count": 15,
395 | "metadata": {},
396 | "outputs": [
397 | {
398 | "data": {
399 | "text/plain": [
400 | "[]"
401 | ]
402 | },
403 | "execution_count": 15,
404 | "metadata": {},
405 | "output_type": "execute_result"
406 | },
407 | {
408 | "data": {
409 | "image/png": "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\n",
410 | "text/plain": [
411 | ""
412 | ]
413 | },
414 | "metadata": {
415 | "needs_background": "light"
416 | },
417 | "output_type": "display_data"
418 | }
419 | ],
420 | "source": [
421 | "x = [1, 2, 3, 4, 5, 6, 7]\n",
422 | "y1 = get_real(-1)\n",
423 | "y2 = get_vis(-1)\n",
424 | "fig, ax = plt.subplots(figsize=(15, 5))\n",
425 | "ax.plot(x, y1, 'ch-', markersize=10)\n",
426 | "ax.plot(x, y2, 'ys-', markersize=10)"
427 | ]
428 | },
429 | {
430 | "cell_type": "code",
431 | "execution_count": 167,
432 | "metadata": {},
433 | "outputs": [
434 | {
435 | "data": {
436 | "image/png": "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\n",
437 | "text/plain": [
438 | ""
439 | ]
440 | },
441 | "metadata": {
442 | "needs_background": "light"
443 | },
444 | "output_type": "display_data"
445 | },
446 | {
447 | "data": {
448 | "text/plain": [
449 | "array([0.95333787, 3.40088556])"
450 | ]
451 | },
452 | "execution_count": 167,
453 | "metadata": {},
454 | "output_type": "execute_result"
455 | }
456 | ],
457 | "source": [
458 | "x_data = np.array(y1)\n",
459 | "\n",
460 | "y_data = np.array(y2)\n",
461 | "\n",
462 | "poly = np.polyfit(x_data, y_data, deg=1)\n",
463 | "\n",
464 | "plt.plot(x_data, y_data, 'o')\n",
465 | "\n",
466 | "plt.plot(x_data, np.polyval(poly, x_data))\n",
467 | "\n",
468 | "plt.show()\n",
469 | "poly"
470 | ]
471 | },
472 | {
473 | "cell_type": "code",
474 | "execution_count": 7,
475 | "metadata": {},
476 | "outputs": [
477 | {
478 | "data": {
479 | "image/png": "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\n",
480 | "text/plain": [
481 | ""
482 | ]
483 | },
484 | "metadata": {
485 | "needs_background": "light"
486 | },
487 | "output_type": "display_data"
488 | },
489 | {
490 | "data": {
491 | "text/plain": [
492 | "array([-2.44332198e-03, 1.76012475e-01, -4.58949704e+00, 5.31642494e+01,\n",
493 | " -2.57338653e+02, 3.41987935e+02])"
494 | ]
495 | },
496 | "execution_count": 7,
497 | "metadata": {},
498 | "output_type": "execute_result"
499 | }
500 | ],
501 | "source": [
502 | "x_data = np.array(y1)\n",
503 | "\n",
504 | "y_data = np.array(y2)\n",
505 | "\n",
506 | "poly = np.polyfit(x_data, y_data, deg=5)\n",
507 | "\n",
508 | "plt.plot(x_data, y_data, 'o')\n",
509 | "\n",
510 | "plt.plot(x_data, np.polyval(poly, x_data))\n",
511 | "\n",
512 | "plt.show()\n",
513 | "poly"
514 | ]
515 | },
516 | {
517 | "cell_type": "markdown",
518 | "metadata": {},
519 | "source": [
520 | "各种分析过后,仍无法做出预测。。。。。"
521 | ]
522 | },
523 | {
524 | "cell_type": "markdown",
525 | "metadata": {},
526 | "source": [
527 | "结论:双色球是无法预测的"
528 | ]
529 | },
530 | {
531 | "cell_type": "markdown",
532 | "metadata": {},
533 | "source": [
534 | "---"
535 | ]
536 | },
537 | {
538 | "cell_type": "markdown",
539 | "metadata": {},
540 | "source": [
541 | "#### 评阅意见反馈"
542 | ]
543 | },
544 | {
545 | "cell_type": "markdown",
546 | "metadata": {},
547 | "source": [
548 | "\n",
549 | "hcccom 提交的《双色球历史数据统计预测》项目挑战报告初步达到课程挑战要求,但仍然有很多地方值得完善。\n",
550 | " \n",
551 | "数据采集部分内容不错,能采集完整的双色球投注数据。但缺乏必要的解释和代码注释。数据分析和处理阶段仅对各号球的出现频次做了统计,选择的柱形图虽然合理但内容较为单薄。这里,建议可以对连续 2 球或者多球的出现频次统计分析。或者分析不同位置各号球的出现频次,或许从统计学角度更有意义。\n",
552 | " \n",
553 | "「取一组」小节之后没有看明白分析的用意,或许是想预测各号球如何出现?不过这样肯定无法完成的。回归分析显然不能用于这里的预测过程。\n",
554 | " \n",
555 | "总之,该挑战报告有 2 点值得改善的地方:\n",
556 | "\n",
557 | "- 补充陈述内容,让阅读者知道每一步的大致操作用意。整个分析报告几乎没有解释性语句,非常不赞同这样做。数据分析的过程很重要,实际上阐述结论和讲好一个故事更加重要。\n",
558 | "\n",
559 | "- 分析思路没有理清,显然双色球出现是随机事件,这是无法通过回归分析完成的。所以,挑战的选题从一开始就不太理想。实际上,就算是真实的数据分析任务,也不建议去做彩票预测,因为就算从概率上得到了一些高频次组合方式,但没有明确的指导意义。\n",
560 | "\n",
561 | "代码方面,注意不用写重复冗余代码(类似 plt.show() 在同单元格多次出现)。后期在书写代码时注意按照 PEP8 格式化即可。VS Code 等 IDE 带有相关格式化插件,Jupyter Notebook 也可以通过安装 jupyter_contrib_nbextensions 拓展开启相关插件自动完成代码格式化。\n",
562 | " \n",
563 | "总之,通过该报告可以判定学员初步达到我们课程预设的培养目标,但仍需要继续学习和加深对数据分析各环节的思考。希望 hcccom 后续再通过书籍等拓展更多相关的数据分析和挖掘知识,并结合自己的兴趣及专业特长在数据分析的道路上越走越好。\n",
564 | "
\n",
565 | "\n",
566 | " \n",
567 | "楼+ 数据分析和挖掘课程组
\n",
568 | "2018 年 12 月 17 日
"
569 | ]
570 | },
571 | {
572 | "cell_type": "markdown",
573 | "metadata": {},
574 | "source": [
575 | "---"
576 | ]
577 | }
578 | ],
579 | "metadata": {
580 | "kernelspec": {
581 | "display_name": "Python 3",
582 | "language": "python",
583 | "name": "python3"
584 | },
585 | "language_info": {
586 | "codemirror_mode": {
587 | "name": "ipython",
588 | "version": 3
589 | },
590 | "file_extension": ".py",
591 | "mimetype": "text/x-python",
592 | "name": "python",
593 | "nbconvert_exporter": "python",
594 | "pygments_lexer": "ipython3",
595 | "version": "3.7.1"
596 | }
597 | },
598 | "nbformat": 4,
599 | "nbformat_minor": 2
600 | }
601 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 实验楼在线教育
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Mindmaps/README.md:
--------------------------------------------------------------------------------
1 | - [点击下载全部思维导图](https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/shiyanlou/louplus-dm/tree/master/Mindmaps)
2 |
--------------------------------------------------------------------------------
/Mindmaps/louplus-dm-week1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiyanlou/louplus-dm/52764983b7080c3ca760e38c38c9a71cf0c2ed3e/Mindmaps/louplus-dm-week1.png
--------------------------------------------------------------------------------
/Mindmaps/louplus-dm-week2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiyanlou/louplus-dm/52764983b7080c3ca760e38c38c9a71cf0c2ed3e/Mindmaps/louplus-dm-week2.png
--------------------------------------------------------------------------------
/Mindmaps/louplus-dm-week3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiyanlou/louplus-dm/52764983b7080c3ca760e38c38c9a71cf0c2ed3e/Mindmaps/louplus-dm-week3.png
--------------------------------------------------------------------------------
/Mindmaps/louplus-dm-week4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiyanlou/louplus-dm/52764983b7080c3ca760e38c38c9a71cf0c2ed3e/Mindmaps/louplus-dm-week4.png
--------------------------------------------------------------------------------
/Mindmaps/louplus-dm-week5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiyanlou/louplus-dm/52764983b7080c3ca760e38c38c9a71cf0c2ed3e/Mindmaps/louplus-dm-week5.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
蓝桥云课《楼+ 数据分析与挖掘实战》课程仓库|课程报名
4 |
5 |
6 |
7 |
8 | 主分支下方包含最新课程的参考答案,历史开班课程的参考答案移步相应分支查看。
9 |
10 | ### 其他班级
11 |
12 | - [第 12-13 期挑战参考答案](https://github.com/shiyanlou/louplus-dm/tree/v3/Answers)
13 | - [第 07-11 期挑战参考答案](https://github.com/shiyanlou/louplus-dm/tree/v2/Answers)
14 | - [第 01-06 期挑战参考答案](https://github.com/shiyanlou/louplus-dm/tree/master/Answers)
15 |
16 | ### 优秀报告
17 |
18 | - [优秀项目挑战比赛报告](https://github.com/shiyanlou/louplus-dm/tree/master/Assignments)
19 |
--------------------------------------------------------------------------------