Несколько дней назад я написал гусенику (с 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”