- 来源 | 愿码(ChainDesk.CN)内容编辑
- 愿码Slogan | 连接每个程序员的故事
- 网站 | http://chaindesk.cn
- 愿码愿景 | 打造全学科IT系统免费课程,助力小白用户、初级工程师0成本免费系统学习、低成本进阶,帮助BAT一线资深工程师成长并利用自身优势创造睡后收入。
- 官方公众号 | 愿码 | 愿码服务号 | 区块链部落
- 免费加入愿码全思维工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码
本文阅读时长:10min
在本文中,我们将探讨如何利用Python的强大功能来收集和处理来自GitHub的数据并使其准备好分析。
GitHub采用广泛使用的版本控制方法,通过在编程领域实现社交网络功能,将编码提升到最高水平。GitHub允许您创建代码存储库并提供多种协作功能,错误跟踪,功能请求,任务管理和维基。它拥有大约2000万用户和5700万个代码库(来源:维基百科)。这些统计数据很容易证明这是程序员最具代表性的平台。它也是几个开源项目的平台,这些项目为软件开发领域做出了巨大贡献。假设GitHub使用了最新的编程工具和技术,分析GitHub可以帮助我们检测最流行的技术。存储库在GitHub上的受欢迎程度是通过它从社区收到的提交数量来评估的。我们将在本文中使用GitHub API来收集具有最多提交数量的存储库的数据,然后发现其中最流行的技术。
范围和流程
GitHub API允许我们获取有关用户提交的公共代码存储库的信息。它涵盖了许多开源,教育和个人项目。我们的重点是找到过去几个月的趋势技术和编程语言,并与过去几年的存储库进行比较。我们将收集有关存储库的所有元信息,例如:
- Name:存储库的名称
- Description:存储库的描述
- Watchers:人们关注存储库并获得有关其活动的通知
- Forks :用户将存储库克隆到自己的帐户
- Open Issues:提交的有关存储库的问题
我们将使用这些数据,定性和定量信息的组合,来识别最新趋势和微弱信号。该过程可以通过下图中显示的步骤表示:
获取数据
在使用API之前,我们需要设置授权。API允许您访问所有公开可用的数据,但某些端点需要用户权限。您可以使用应用程序设置创建具有某些特定范围访问权限的新令牌。范围取决于您的应用程序的需求,例如访问用户电子邮件,更新用户配置文件等。 密码授权仅在某些情况下需要,例如用户授权的应用程序访问。在这种情况下,您需要提供用户名或电子邮件以及密码。
所有API访问均通过HTTPS进行,并可从https://api.github.com/ 域访问。所有数据都以JSON的形式发送和接收。
速率限制
GitHub Search API旨在帮助查找特定项(存储库,用户等)。速率限制策略允许每次搜索最多1,000个结果。对于使用基本身份验证,OAuth或客户端ID和密钥的请求,您每分钟最多可以发出30个请求。对于未经身份验证的请求,速率限制允许您每分钟最多发出10个请求。
连接到GitHub
GitHub提供了一个搜索端点,它返回与查询匹配的所有存储库。随着我们的进展,在分析的不同步骤中,我们将更改变量q(查询)的值。在第一部分中,我们将检索自2017年1月1日以来创建的所有存储库,然后我们将比较前几年的结果。
首先,我们初始化一个空列表结果,该结果存储有关存储库的所有数据。其次,我们使用API所需的参数构建get请求。我们每个请求只能获得100个结果,因此我们必须使用分页技术来构建完整的数据集。
results = []
q = "created:>2017-01-01"
def search_repo_paging(q):
url = 'https://api.github.com/search/repositories'
params = {'q' : q, 'sort' : 'forks', 'order': 'desc', 'per_page' : 100}
while True:
res = requests.get(url,params = params)
result = res.json()
results.extend(result['items'])
params = {}
try:
url = res.links['next']['url']
except:
break
在第一个请求中,我们必须将所有参数传递给请求中的方法。然后,我们为每个下一页创建一个新请求,可以在链接中找到包含所有其他参数的资源的完整链接。这就是我们清空params词典的原因。
GET res.links'next'. res.
重复该操作,直到字典中没有下一页键。对于其他数据集,我们修改搜索查询的方式是从前几年检索存储库。例如,要从2015年获取数据,我们定义以下查询:res.links
q = "created:2015-01-01..2015-12-31"
为了找到合适的存储库,API提供了大量的查询参数。使用限定符系统可以高精度地搜索存储库。从主搜索参数q开始,我们有以下选项:
- sort:设置为forks,因为我们有兴趣找到具有最大数量的分支的存储库(您还可以按星数或更新时间排序)
- order:设置为降序
- per_page:设置为返回的最大存储库数量
当然,搜索参数q 可以包含多个限定符组合。
数据拉动
我们通过GitHub API收集的数据量使其适合内存。我们可以直接在pandas数据帧中处理它。如果需要更多数据,我们建议将其存储在数据库中,例如MongoDB。
我们使用JSON工具将结果转换为干净的JSON并创建数据帧。
from pandas.io.json import json_normalize
import json
import pandas as pd
import bson.json_util as json_util
sanitized = json.loads(json_util.dumps(results))
normalized = json_normalize(sanitized)
df = pd.DataFrame(normalized)
数据框df 包含与GitHub API返回的所有结果相关的列。我们可以通过输入以下内容列出它们:
Df.columns
Index(['archive_url', 'assignees_url', 'blobs_url', 'branches_url',
'clone_url', 'collaborators_url', 'comments_url', 'commits_url',
'compare_url', 'contents_url', 'contributors_url', 'default_branch',
'deployments_url', 'description', 'downloads_url', 'events_url',
'Fork',
'forks', 'forks_count', 'forks_url', 'full_name', 'git_commits_url',
'git_refs_url', 'git_tags_url', 'git_url', 'has_downloads',
'has_issues', 'has_pages', 'has_projects', 'has_wiki', 'homepage',
'hooks_url', 'html_url', 'id', 'issue_comment_url',
'Issue_events_url',
'issues_url', 'keys_url', 'labels_url', 'language', 'languages_url',
'merges_url', 'milestones_url', 'mirror_url', 'name',
'notifications_url', 'open_issues', 'open_issues_count',
'owner.avatar_url', 'owner.events_url', 'owner.followers_url',
'owner.following_url', 'owner.gists_url', 'owner.gravatar_id',
'owner.html_url', 'owner.id', 'owner.login',
'Owner.organizations_url',
'owner.received_events_url', 'owner.repos_url', 'owner.site_admin',
'owner.starred_url', 'owner.subscriptions_url', 'owner.type',
'owner.url', 'private', 'pulls_url', 'pushed_at', 'releases_url',
'score', 'size', 'ssh_url', 'stargazers_count', 'stargazers_url',
'statuses_url', 'subscribers_url', 'subscription_url', 'svn_url',
'tags_url', 'teams_url', 'trees_url', 'updated_at', 'url',
'Watchers',
'watchers_count', 'year'],
dtype='object')
然后,我们选择将用于进一步分析的变量子集。我们跳过与URL、所有者信息或ID 相关的所有技术变量 。其余列包含的信息很可能有助于我们识别新的技术趋势:
- description:存储库的用户描述
- watchers_count:观察者人数
- size:存储库的大小(以KB为单位)
- forks_count:叉的数量
- open_issues_count:未解决的问题数量
- language:编写存储库的编程语言
我们选择了衡量存储库流行度的标准。此数字表示有多少人对该项目感兴趣。 但是,我们也可以使用它给我们提供有关流行度的略有不同的信息。后者表示实际使用代码的人数,因此它与不同的组相关。watchers_count forks_count
数据处理
在上一步中,我们构建了原始数据,现在可以进行进一步分析。 我们的目标是分析两种类型的数据:
- 描述中的文字数据
- 其他变量的数值数据
它们中的每一个都需要不同的预处理技术。让我们看一下Detail 中的每种类型。
文本数据
对于第一种,我们必须创建一个包含已清理字符串的新变量。我们将分三个步骤完成,这些步骤已在前几章中介绍过:
- 选择英文说明
- 符号化
- 停用词
由于我们只处理英语数据,因此我们应该删除所有用其他语言编写的描述。这样做的主要原因是每种语言都需要不同的处理和分析流程。如果我们留下俄语或中文的描述,我们会得到非常嘈杂的数据,而这些数据是我们无法解释的。因此,可以说我们正在分析英语世界的趋势。
首先,我们删除description列中的所有空字符串。
df = df.dropna(subset=['description'])
为了删除非英语描述,我们必须首先检测每个文本中使用的语言。为此,我们使用了一个名为langdetect 的库,该库基于 Google语言检测项目。
from langdetect import detect
df['lang'] = df.apply(lambda x: detect(x['description']),axis=1)
我们创建一个包含所有预测的新列。我们看到不同的语言, 例如en (英语),zh-cn (中文),vi (越南语)或ca (加泰罗尼亚语)。
df['lang']
0 en
1 en
2 en
3 en
4 en
5 zh-cn
在我们的数据集中,en占所有存储库的78.7%。我们现在只选择那些带有英文描述的存储库:
df = df[df['lang'] == 'en']
在下一步中,我们将使用预处理的文本数据创建一个新的clean列。我们执行以下代码来执行标记化并删除停用词:
import nltk
from nltk import word_tokenize
from nltk.corpus import stopwords
def clean(text = '', stopwords = []):
#tokenize
tokens = word_tokenize(text.strip())
#lowercase
clean = [i.lower() for i in tokens]
#remove stopwords
clean = [i for i in clean if i not in stopwords]
#remove punctuation
punctuations = list(string.punctuation)
clean = [i.strip(''.join(punctuations)) for i in clean if i not in punctuations]
return " ".join(clean)
df['clean'] = df['description'].apply(str) #make sure description is a string
df['clean'] = df['clean'].apply(lambda x: clean(text = x, stopwords = stopwords.words('english')))
Finally, we obtain a clean column which contains cleaned English descriptions, ready for analysis:
df['clean'].head(5)
0 roadmap becoming web developer 2017
1 base repository imad v2 course application ple…
2 decrypted content eqgrp-auction-file.tar.xz
3 shadow brokers lost translation leak
4 learn design large-scale systems prep system d...
数值数据
对于数值数据,我们将统计检查值的分布以及是否存在任何缺失值:
df[['watchers_count','size','forks_count','open_issues']].describe()
我们看到在所有四个变量中没有缺失值:watchers_count、size、forks_count和open_issues。watchers_count的值从0到20,792不等,而最小的fork数是33,并上升到2,589。前四分之一的存储库没有开放问题,而前25%的存储库有超过12个问题。值得注意的是,在我们的数据集中,有一个包含458个开放问题的存储库。
一旦我们完成了数据的预处理,我们的下一步就是分析它,以便从中获得可操作的见解。