乐趣区

使用Python挖掘GitHub的流行趋势上

  • 来源 | 愿码 (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 个开放问题的存储库。

一旦我们完成了数据的预处理,我们的下一步就是分析它,以便从中获得可操作的见解。

退出移动版