附录 2 单星项目的解决方案
此附录挑选了一些(单星)项目,给出了参考的解决方案。这些解决方案使用了最具Python风格的方式。如果你的解决方案与给出的不一致,也没有必要纠结!编程问题的解决方案本来就不止一种,这就如同有多种描写爱情和死亡的方法一样。
Hello, World!
编写一个在Python命令行输出“Hello, World!”的程序(第1章的问题)。
solution-hello.py
# 尊重传统 print("Hello, World!")
词频计数器
编写一个程序,用于下载用户请求的网页,并给出网页中使用频率最高的十个词,所有词不区分大小写。出于练习的目的,可以简单地假设一个词由正则表达式r"\w+"确定(第2章的问题)。
solution-counter.py
import urllib.request, re from collections import Counter # 建立与用户以及与网络的会话 url = input("Enter the URL: ") try: page = urllib.request.urlopen(url) except: print("Cannot open %s" % url) quit() # 读取页面,并完成部分规范化操作 doc = page.read().decode().lower() # 将文本切分为词语 words = re.findall(r"\w+", doc) # 构建计数器并给出结果 print(Counter(words).most_common(10))
失效链接检测器
编写一个程序,基于一个给定网页的URL,报出页面中失效链接的名称和地址。出于练习的目的,约定当使用urllib.request.urlopen()打开链接失败时,则认为链接失效(第3章的问题)。
solution-broken_link.py
import urllib.request, urllib.parse import bs4 as BeautifulSoup # 建立与用户以及与网络的会话 base = input("Enter the URL: ") try: page = urllib.request.urlopen(base) except: print("Cannot open %s" % base) quit() # 准备soup soup = BeautifulSoup.BeautifulSoup(page) # 提取链接,并用(名称,网址)的元组表示 links = [(link.string, link["href"]) for link in soup.find_all("a") if link.has_attr("href")] # 尝试打开每个链接 broken = False for name, url in links: # 将base和链接目标组合在一起 dest = urllib.parse.urljoin(base, url) try: page = urllib.request.urlopen(dest) page.close() except: print("Link \"%s\" to \"%s\" is probably broken." % (name, dest)) broken = True # 显示好消息! if not broken: print("Page %s does not seem to have broken links." % base)
MySQL文件索引器
编写一个Python程序,对于给定文件中的每个单词,记录如下信息到MySQL数据库中:单词本身(不是词干!)、单词在文件中的序数(从1开始),以及单词的词性标记。使用NLTK WordPunct-Tokenizer(参考第16单元第2小节)来识别单词。假设这些单词比较短,数据类型可以使用MySQL的TINYTEXT。设计数据库模式,创建所有必需的表,并在正式开始编写Python代码之前,通过命令行来试用一下设计出来的表(第4章的问题)。
该解决方案由两个文件组成:一个是设置表的MySQL脚本,另一个是执行索引的Python程序。
solution-mysql_indexer.sql
CREATE TABLE IF NOT EXISTS indexer(id INT PRIMARY KEY AUTO_INCREMENT, ts TIMESTAMP, word TINYTEXT, position INT, pos VARCHAR(8));
solution-mysql-indexer.py
import nltk, pymysql infilename = input("Enter the name of the file to index: ") # 结合你的MySQL服务器的设置改变本行 conn = pymysql.connect(user="dsuser", passwd="badpassw0rd", db="dsbd") cur = conn.cursor() QUERY = "INSERT INTO indexer (word,position,pos) VALUES " wpt = nltk.WordPunctTokenizer() offset = 1 with open(infilename) as infile: # 使用增量方式处理文本,每次处理一行 # 不论如何,一个词不可能跨行分布 for text in infile: # 分词并加入POS标签 pieces = enumerate(nltk.pos_tag(wpt.tokenize(text))) # 创建一个查询命令;别忘了要避开待查询的词! words = ["(\"%s\",%d,\"%s\")" % (conn.escape_string(w), i + offset, conn.escape_string(pos)) for (i, (w, pos)) in pieces] # 执行查询命令 if words: cur.execute(QUERY + ','.join(words)) # 移动词的位置指针 offset += len(words) # 提交更改 conn.commit() conn.close()
数组微分器
(函数的)部分和近似等价于(函数的)积分。事实上,微积分理论就把积分定义为无穷小元素的无限求和。(函数的)部分差arri+1-arri近似等价于(函数的)导数。numpy没有提供用于计算数组部分差的工具。请编写一个程序,对于一个给定的数组arr,计算数组项的部分差。在本练习中假设数组为数值数组(第5章的问题)。
solution-difference.py
import numpy as np # 用于测试的合成数据 array = np.random.binomial(5, 0.5, size=100) # 计算数组部分差:切片&广播! diff = array[1:] - array[:-1]
猞猁的捕获量
写一个程序,使用每年加拿大猞猁的捕获量1给出每十年的猞猁捕获总量,并将结果按逆序排列(最“有效益的”十年排在前面)。如果cache目录中不存在数据文件,则程序自动将数据下载到cache目录中。如果cache目录不存在,则程序将自动创建该目录。程序将计算结果保存到doc目录下的CSV文件中。如果doc目录不存在,则程序将自动创建该目录(第6章的问题)。
solution-lynx.py
import os, pandas as pd import urllib.request # 一些“常量” SRC_HOST = "https://vincentarelbundock.github.io" FILE = "/lynx.csv" SRC_NAME = SRC_HOST + "/Rdatasets/csv/datasets" + FILE CACHE = "cache" DOC = "doc" # 在需要时创建目录 if not os.path.isdir(CACHE): os.mkdir(CACHE) if not os.path.isdir(DOC): os.mkdir(DOC) # 检查文件是否缓存;如未缓存就进行缓存处理 if not os.path.isfile(CACHE + FILE): try: src = urllib.request.urlopen(SRC_NAME) lynx = pd.read_csv(src) except: print("Cannot access %f." % SRC_NAME) quit() # 创建数据frame lynx.to_csv(CACHE + FILE) else: lynx = pd.read_csv(CACHE + FILE) # 加入“decade”列 lynx["decade"] = (lynx['time'] / 10).round() * 10 # 求和并排序 by_decade = lynx.groupby("decade").sum() by_decade = by_decade.sort_values(by="lynx", ascending=False) # 保存结果 by_decade["lynx"].to_csv(DOC + FILE)
中心性的相关问题
从斯坦福大网络数据集2中下载Epinions.com网站用户的社交网络图,并提取出规模排名第十的社区。编写一个程序,计算并显示第7章中提到的所有网络中心性度量之间的两两相关性;加入集聚系数可以使问题变得更加有趣(第7章的问题)。建议你使用pandas的frame来存储所有中心性。你可能需要阅读第47单元第2小节来了解如何使用pandas计算相关性。
是否存在强相关的一对中心性?
solution-centrality.py
import networkx as nx, community import pandas as pd # 导入network模块 G = nx.read_adjlist(open("soc-Epinions1.txt", "rb")) # 提取社区结构并用series保存 partition = pd.Series(community.best_partition(G)) # 找出10个最大社区的索引 top10 = partition.value_counts().index[9] # 提取10大社区 # 注意节点的标签是字符串! subgraph = partition[partition == top10].index.values.astype('str') F = G.subgraph(subgraph) # 计算网络的度量 df = pd.DataFrame() df["degree"] = pd.Series(nx.degree_centrality(F)) df["closeness"] = pd.Series(nx.closeness_centrality(F)) df["betweenness"] = pd.Series(nx.betweenness_centrality(F)) df["eigenvector"] = pd.Series(nx.eigenvector_centrality(F)) df["clustering"] = pd.Series(nx.clustering(F)) # 计算相关性 print(df.corr()) ➾ degree closeness betweenness eigenvector clustering ➾ degree 1.000000 0.247377 0.871812 0.738836 0.100259 ➾ closeness 0.247377 1.000000 0.169449 0.547228 0.024052 ➾ betweenness 0.871812 0.169449 1.000000 0.527290 -0.015759 ➾ eigenvector 0.738836 0.547228 0.527290 1.000000 0.143070 ➾ clustering 0.100259 0.024052 -0.015759 0.143070 1.000000
度中心性与中介中间性以及特征矢量中心性呈强的线性相关关系。
美国派
编写一个程序,将美国的所有州按首字母分组,并用一个饼图显示分组结果或保存为PDF文件。为了完成该项目,你需要用到州的名称或其缩写的列表,这个列表可以从命名网站获取3(第8章的问题)。
solution-states-pie.py
import pandas as pd import matplotlib, matplotlib.pyplot as plt def initial(word): return word[0] # 读取州名(可以使用任何你喜欢的数据源!) states = pd.read_csv("states.csv", names=("State", "Standard", "Postal", "Capital")) # 选取一种优美的绘图样式 matplotlib.style.use("ggplot") # 绘图 plt.axes(aspect=1) states.set_index('Postal').groupby(initial).count()['Standard'].plot.pie() plt.title("States by the First Initial") plt.ylabel("") plt.savefig("../images/states-pie.pdf")
得到的饼图如下所示:
21世纪标准普尔500指数
编写一个程序,给出21世纪标准普尔500指数收盘价的一些基本统计量:平均值、标准差、偏斜度以及收盘价和交易量之间的相关性。为了确定得出的相关性是否可靠,可以从Yahoo! Finance4下载历史价格。应注意,21世纪是从2001年1月1日开始的(第9章的问题)。
鉴于新下载的数据不同于本示例中使用的数据,你的答案可能也会不同。
solution-sap.py
import pandas as pd from scipy.stats import pearsonr # 读取数据 sap = pd.read_csv("sapXXI.csv").set_index("Date") # 计算并给出统计值的报告 print("Mean:", sap["Close"].mean()) print("Standard deviation:", sap["Close"].std()) print("Skewness:", sap["Close"].skew()) print("Correlation:\n", sap[["Close", "Volume"]].corr()) _, p = pearsonr(sap["Close"], sap["Volume"]) print("p-value:", p) ➾ Mean: 1326.35890044 ➾ Standard deviation: 332.784759688 ➾ Skewness: 0.858098114571 ➾ Correlation: ➾ Close Volume ➾ Close 1.000000 0.103846 ➾ Volume 0.103846 1.000000 ➾ p-value: 1.5301705092e-10
结果表明相关性是非常可靠的,但非常微不足道。
MOSN分类
编写一个程序,通过注册用户数量和全球Alexa页面排名⑤,对大量的在线社交网站进行分类。由于站点的排名及其大小差异很大,所以应使用对数尺度来进行聚类和结果呈现(第10章的问题)。
solution-mosn.py
import pandas as pd, numpy as np import sklearn.cluster, sklearn.preprocessing import matplotlib, matplotlib.pyplot as plt # 读取数据 mosn = pd.read_csv('mosn.csv', thousands=',', names=('Name', 'Description', 'Date', 'Registered Users', 'Registration', 'Alexa Rank')) columns = ['Registered Users', 'Alexa Rank'] # 删除有缺失数据和零值的行 good = mosn[np.log(mosn[columns]).notnull().all(axis=1)].copy() # 聚类 kmeans = sklearn.cluster.KMeans() kmeans.fit(np.log(good[columns])) good["Clusters"] = kmeans.labels_ # 找出Facebook fb = good.set_index('Name').ix['Facebook']['Clusters'] # 选取一种优美的绘图样式 matplotlib.style.use("ggplot") # 显示结果 ax = good.plot.scatter(columns[0], columns[1], c="Clusters", cmap=plt.cm.Accent, s=100) plt.title("Massive online social networking sites") plt.xscale("log") plt.yscale("log") # 标记出最出名的站点 def add_abbr(site): if site['Clusters'] == fb: _ = ax.annotate(site["Name"], site[columns], xytext=(1, 5), textcoords="offset points", size=8, color="darkslategrey") good.apply(add_abbr, axis=1) plt.savefig("../images/mosn.png")
1vincentarelbundock.github.io/Rdatasets/csv/datasets/lynx.csv
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论