Рубрики
Без рубрики

Исследовательский анализ данных GitHub

Фон несколько дней назад я написал гусенику (с Nodejs и Sequelize), что выбирает … Теги с Python, Datascity, Github, Showdev.

Несколько дней назад я написал гусенику (с Nodejs и Sequelize ), которые выбирают общедоступные данные из Github API GraphQL . Точнее, я скачал информацию о пользователях, репозиториях, языках программирования и темы.

После запуска гусенично на несколько дней я оказался 154 248 пользовательских профилей , 993,919 репозитории и 351 Языки Многие из которых я никогда не слышал (например, знал о Pogoscript ?). Однако, хотя моя база данных MySQL уже составляет 953 МБ по размеру только с этими данными, я едва сказал 0,4% всех профилей пользователей (~ 31 млн.).

Первая (менее обширная) версия моей базы данных – которую я выполнил следующие анализы – выглядел так.

Хотя можно утверждать, что собранные мной данные не имеют репрезентативного размера выборки, я все еще хотел сделать некоторый анализ данных на нем – просто для удовольствия.

Для выполнения анализа я использовал Python 3 с пандами и MATPLOTLIB.

import apriori
import pymysql
import pandas as pd
import matplotlib.pyplot as plt
from sqlalchemy import create_engine

%matplotlib inline

pymysql.install_as_MySQLdb()

sql_engine = create_engine('mysql://user:heheyouwish@localhost:3306/github_data', echo=False)
connection = sql_engine.raw_connection()

Самые популярные языки программирования

Одной из первых и наиболее очевидных вещей, чтобы проверить (ради краткости, я пропущу основные статистики набора данных, такие как подсчет, среднее значение, дисперсия, …), является на каких языках наиболее широко используются.

df_top_langs = pd.read_sql_query('''
    select LanguageName, count(LanguageName) as count from RepositoryLanguages
    group by LanguageName
    order by count(LanguageName) desc
    limit 10;
''', con=connection)
df_top_langs.set_index('LanguageName').plot.bar(figsize=(12,8))

Не слишком удивительно, типичный веб-стог, состоящий из JavaScript, HTML и CSS, является одним из самых популярных языков программирования, в соответствии с тем, как часто они появляются в репозиториях.

Наименее популярные языки программирования

Немного интереснее, чтобы увидеть, какие языки программирования происходят наименьшее.

df_last_langs = pd.read_sql_query('''
    select LanguageName, count(LanguageName) as count from RepositoryLanguages
    group by LanguageName
    order by count(LanguageName) asc
    limit 10;
''', con=connection)
print(df_last_langs)

Вот результаты. Вы слышали о любом из них? Я не сделал.

  LanguageName  count
0          Nit      1
1       Myghty      1
2   Public Key      1
3  DCPU-16 ASM      1
4   TI Program      1
5        Genie      1
6           Ox      1
7   PogoScript      1
8        Cirru      1
9        JFlex      2

Давайте проанализируем навыки пользователей с точки зрения языков. Я решил рассмотреть вопрос о том, чтобы пользователь «квалифицирован» на определенном языке, если на этом языке не менее 10% ее репозиториев на этом языке.

N = int(1e7)
MIN_SUPP = .0005
MIN_CONF = .45
MIN_LANG_RATIO = .1

df_skills = pd.read_sql_query(f'''
    select RepositoryLanguages.LanguageName, RepositoryLanguages.size, Users.login, Users.location from RepositoryLanguages
    left join Repositories on Repositories.id = RepositoryLanguages.RepositoryId
    right join Users on Users.login = Repositories.userLogin
    limit {N}
''', con=connection)

df_skills = df_skills.merge(pd.DataFrame(df_skills.groupby('login')['size'].sum()), how='left', on='login').rename(columns={'size_x': 'size', 'size_y': 'totalSize'})
df_skills = df_skills[df_skills['totalSize'] > 0]
df_skills['sizeRatio'] = df_skills['size'] / df_skills['totalSize']

print(f"{df_skills['login'].unique().size} users")
print(f"{df_skills['LanguageName'].unique().size} languages")

# Output:
# 130402 users
# 351 languages

Правила ассоциации

То, что я хотел посмотреть, это комбинации различных навыков, то есть языки, которые обычно встречаются вместе как навыки разработчиков. Один подход, чтобы получить понимание, подобные это, – это мои данные для Правила ассоциации , например Использование алгоритма, как Априори (как я сделал). Реализация, которую я использовал, был асани/Априори Отказ

user_langs = df_skills[df_skills['sizeRatio'] >= MIN_LANG_RATIO].groupby('login')['LanguageName'].apply(set).values
items1, rules1 = apriori.runApriori(user_langs, MIN_SUPP, MIN_CONF)
rules1 = sorted(rules1, key=lambda e: e[1], reverse=True)
print(rules1)

Вывод:

[((('ShaderLab',), ('C#',)), 0.904),
 ((('Vue',), ('JavaScript',)), 0.671277997364954),
 ((('Vue', 'CSS'), ('JavaScript',)), 0.656140350877193),
 ((('GLSL',), ('C#',)), 0.625),
 ((('CMake',), ('C++',)), 0.6229508196721312),
 ((('CSS',), ('JavaScript',)), 0.5807683959192532),
 ((('Tcl',), ('Python',)), 0.5658914728682171),
 ((('Kotlin',), ('Java',)), 0.5655375552282769),
 ((('ASP',), ('C#',)), 0.5488215488215488),
 ((('Vue', 'HTML'), ('JavaScript',)), 0.5404411764705882),
 ((('CoffeeScript',), ('JavaScript',)), 0.5339578454332553),
 ((('CSS', 'PHP'), ('JavaScript',)), 0.5116117850953206),
 ((('Elm',), ('JavaScript',)), 0.4951923076923077),
 ((('CSS', 'HTML'), ('JavaScript',)), 0.4906486271388778),
 ((('Smarty',), ('PHP',)), 0.4788732394366197),
 ((('TypeScript',), ('JavaScript',)), 0.4739540607054964),
 ((('CSS', 'C#'), ('JavaScript',)), 0.464926590538336),
 ((('Groovy',), ('Java',)), 0.4604651162790698)]

Левая часть каждой строки является кортеж кортежей языков программирования, которые представляют правило ассоциации. Правая часть – это Уверенность этого правила.

Например: Читать ((('SaderLab',), ('C #',)), 0.904) как «90% всех людей, которые знают Shaderlab Также знаю C # ».

Результаты отражают здравый смысл. Например, правило, что разработчики, которые знают Vuejs также знать JavaScript Похоже, имеет смысл, учитывая, что Vuejs – это JavaScript Framework. Аналогично, Cmake Это общий инструмент сборки для C ++ , и т.д. Здесь ничего не слишком, кроме этого, я не знал о Shaderlab и GLSL Отказ

Локации

Давайте посмотрим, где из большинства пользователей GitHub. Очевидно, что это только уважает профили, на которых пользователи установили свои места.

df_locations = df1.reindex(['location'], axis=1).groupby('location').size()
df_locations = df_locations.sort_values(ascending=False)[:20]
df_locations.plot.bar(figsize=(12,8))

Очевидно, что San Francisco кажется самым популярным городом для разработчиков (или, по крайней мере, для тех, кто активен в Github).

Навыки по местоположению

Чтобы сделать этот шаг дальше, давайте посмотрим, какие пользователи навыков имеют тенденцию иметь в каких городах.

def language_replace(df):
    df = df.copy()
    # Little bit of manual cleaning
    replace = {'San Francisco': 'San Francisco, CA',
               'Berlin': 'Berlin, Germany',
               'New York': 'New York, NY',
               'London': 'London, UK',
               'Beijing': 'Beijing, China',
               'Paris': 'Paris, France'}
    for (k, v) in replace.items():
        if isinstance(df, pd.DataFrame):
            if k in df.columns and v in df.columns:
                df[k] = df[k] + df[v]
                df = df.drop([v], axis=1, errors='ignore')
        else:
            if k in df.index and v in df.index:
                df[k] = df[k] + df[v]
                #df = df.drop([v], axis=1)
                del df[v]
    return df

langs_by_loc = {}
for l in df_locations.index:
    langs_by_loc[l] = df1[df1['location'] == l][['LanguageName']].groupby('LanguageName').size()
df_loc_langs = pd.DataFrame.from_dict(langs_by_loc).fillna(0)

df_loc_langs = language_replace(df_loc_langs)
df_loc_langs = df_loc_langs.T
df_loc_langs = df_loc_langs.drop([c for c in df_loc_langs.columns if c not in df_top_langs['LanguageName'].values], axis=1)

df_loc_langs = (df_loc_langs.T / df_loc_langs.T.sum()).T # normalize heights
df_loc_langs.plot.bar(stacked=True, figsize=(16,10))

Похоже, нет реальных выходов в распространении навыков разработчиков между различными городами мира. Может быть, вы могли бы сказать это, например, индийцы, как веб-интерфейсы чуть больше, чем взлома командной строки.

Навыки: Карлсруэ против мира

Хотя обзор прохладно, я нашел его еще интереснее, чтобы специально сравнить между городами. Таким образом, на следующем графике я сравниваю навыки программирования, специфичные языком в Карлсрухе (город, где я живу и изучаю) до остальной части в мире.

df_ka = df1[df1['location'] == 'Karlsruhe'][['LanguageName']].groupby('LanguageName').size()
df_ka = pd.DataFrame(df_ka, index=df_ka.index, columns=['Karlsruhe']) / df_ka.sum()
df_world = pd.DataFrame(df_loc_langs.mean(), index=df_loc_langs.mean().index, columns=['World'])
df_compare = df_world.merge(df_ka, how='left', left_index=True, right_index=True)
ax = df_compare.plot.barh(title='Languages: World vs. Karlsruhe', legend=True, figsize=(10,5))
ax.set_xlabel('Percentage (Top 10)')
ax.set_ylabel('Programming Language Skills')

Эти результаты немного удивительны для меня. Ясно, что разработчики, основанные на карлсруге, похоже, не нравится JavaScript по сравнению с миром. Тем не менее, это отличается от того, что я испытывал в нескольких студентах и стажировках здесь.

Технологические стопки проекта

Последнее, но не в последнюю очередь, давайте применим априори еще раз, но на этот раз немного по-другому. Вместо того, чтобы смотреть на пользовательские навыки, давайте посмотрим на языки, которые встречаются вместе на основании для каждого репозитория. И вместо того, чтобы пытаться найти правила, давайте только посмотрим на Частые наборы предметов (которые являются основой для правил). Мое ожидание состояло в том, чтобы вернуть наборы общепринятых технологий.

N = int(1e7)
MIN_SUPP = .0005
MIN_CONF = .45
MIN_LANG_RATIO = .1

df_stacks = pd.read_sql_query(f'''
    select LanguageName, size, RepositoryId from RepositoryLanguages
    order by RepositoryId
    limit {N}
''', con=connection)

df_stacks = df_stacks.merge(pd.DataFrame(df_stacks.groupby('RepositoryId')['size'].sum()), how='left', on='RepositoryId').rename(columns={'size_x': 'size', 'size_y': 'totalSize'})
df_stacks = df_stacks[df_stacks['totalSize'] > 0]
df_stacks['sizeRatio'] = df_stacks['size'] / df_stacks['totalSize']

print(f"{df_stacks['RepositoryId'].unique().size} repositories")
print(f"{df_stacks['LanguageName'].unique().size} languages")

# Output: 
# 853114 repositories
# 351 languages
repo_langs = df_stacks[df_stacks['sizeRatio'] >= MIN_LANG_RATIO].groupby('RepositoryId')['LanguageName'].apply(set).values
items2, rules2 = apriori.runApriori(repo_langs, MIN_SUPP, MIN_CONF)
itemsets2 = sorted(list(filter(lambda i: len(i[0]) > 2, items2)), key=lambda i: i[1], reverse=True)
print(itemsets2)

Вывод:

[(('CSS', 'JavaScript', 'HTML'), 0.04360026913167525),
 (('CSS', 'JavaScript', 'PHP'), 0.0045574213997191465),
 (('Ruby', 'CSS', 'HTML'), 0.004456614239128651),
 (('TypeScript', 'JavaScript', 'HTML'), 0.0042034241613664765),
 (('TypeScript', 'HTML', 'CSS'), 0.0035024627423767517),
 (('Python', 'JavaScript', 'HTML'), 0.002962089474560258),
 (('Python', 'HTML', 'CSS'), 0.002769852563666755),
 (('Ruby', 'JavaScript', 'HTML'), 0.0022400288824236856),
 (('JavaScript', 'HTML', 'PHP'), 0.0022154131804190294),
 (('Ruby', 'CSS', 'JavaScript'), 0.0021532878372644217),
 (('CSS', 'HTML', 'PHP'), 0.0019915275098052547),
 (('JavaScript', 'Objective-C', 'Java'), 0.0018614159420663593),
 (('CSS', 'JavaScript', 'Python'), 0.0017992905989117516),
 (('Python', 'JavaScript', 'Objective-C'), 0.0017735027206211597),
 (('Python', 'JavaScript', 'Java'), 0.001508590879999625),
 (('CSS', 'JavaScript', 'TypeScript'), 0.0014745977677074812),
 (('Python', 'Objective-C', 'Java'), 0.0014066115431231934),
 (('Python', 'JavaScript', 'Objective-C', 'Java'), 0.0013222148505358019),
 (('Vue', 'CSS', 'JavaScript'), 0.0012554008022374501)]

Здесь левая сторона – это наборы часто встречающихся комбинаций языков. Правая сторона – это набор Поддержка , что являются относительными вхождениями, которые устанавливают среди всего набора данных. Очевидно, что многие из них на самом деле являются обычными «техниками», и почти все они являются веб-технологиями. Я думаю, GitHub самый популярен среди веб-разработчиков.

Существует много более сложных анализов, которые могут быть на богатых данных, как это, и, вероятно, такие инструменты, как Бить лучше подходят, чем панды, работающие на крошечном образце. Тем не менее, я использовал этот маленький проект, чтобы улучшить свои навыки EDA и, надеюсь, даст вам, ребята, интересную статью читать. Дайте мне знать, если вам это нравится!

Первоначально опубликовано в muetsch.io

Оригинал: “https://dev.to/n1try/exploratory-analysis-on-github-data-oib”