Как стать автором
Обновить

Code Mining. Могут ли аналитики читать код?

Уровень сложностиСредний
Время на прочтение5 мин
Количество просмотров939

Привет, Хабр! На связи участник профессионального сообщества NTA Губин Никита.

Введение

Code mining — это процесс анализа и извлечения информации из исходного кода для получения полезных данных. Аналитики, имея базовые компетенции в разработке, могут использовать их как дополнительный источник информации для улучшения процессов. Инструмент, о котором я расскажу в посте, разделяет код на логические блоки, что позволит улучшить взаимодействие DS‑специалистов и аналитиков.

Аналитики и код

Почему же аналитикам трудно самостоятельно анализировать исходный код?

Выделим несколько причин:

  • Незнакомые средства, в виде расширенного поиска по составам репозиториев;

  • Непривычное разрозненное расположение информации, которая распределена по умозрительным и непонятным для аналитика признакам;

  • Возможное несоответствие документации с исходным кодом.

Решение

В качестве решения было разработано приложение, которое парсит все файлы проекта с кодом в один excel файл, поделенный на логические блоки:

Пример работы
Пример работы

Преимущество данного решения:

  • Привычный инструмент. Excel — один из основных инструментов аналитика;

  • Код проекта, состоящий из нескольких файлов, собирается в одном месте;

  • За счет структуры файла, у аналитика появляются широкие возможности по фильтрации, анализу и поиску необходимой информации.

Реализация

Код написан на Python и предназначен для разбора кода так же на Python.

В посте будут разобраны ключевые моменты. Полный код доступен по ссылке на Github.

Изначально, необходимо собрать файлы (.py), которые в дальнейшем будем обрабатывать:

#Метод выгрузки данных
def folder(fold,pth,filenames):
    if fold == True:
        filenames = glob(os.path.join(pth, "*.py"))
    elif fold == False:
        for root, dirs, files in os.walk(pth):
            files = [f for f in files if not f[0] == '.']
            dirs[:] = [d for d in dirs if not d[0] == '.']
            for file in files:
                if(file.endswith(".py")):
                    filenames.append(os.path.join(root,file))
    return filenames

Предусмотрено 2 варианта сбора:

  • Только из указанной папки;

  • Из указанной папки и всех подпапок (кроме скрытых). 

Задаем DataFrame со структурой будущего excel файла:

# Создаем DataFrame с соответствующими колонками
col = ['Стратегия', 'Путь', 'Исходная функция', 'Номер строки фрагмента', 'Тип фрагмента', 'Фрагмент']
df = pd.DataFrame(columns=col) 

Построчно обрабатываем файлы:

for i in my_code:
    counter += 1
    # Обрабатываем строку
    i = i.strip(' ')
    # Проверка для записи исходной строки
    if 'def ' not in i:
        ish += i
# Обрабатываем комментарии
if i[0] == '#':
    if per != '':
        perem()
    # Заполняем IF не в одну строку
    if y == 1:
         df.at[row_in_dataframe, 'Стратегия'] = strategy
         df.at[row_in_dataframe, 'Путь'] = path
         df.at[row_in_dataframe, 'Номер строки фрагмента'] = counter
         df.at[row_in_dataframe, 'Тип фрагмента'] = 'Условие IF'
         df.at[row_in_dataframe, 'Фрагмент'] = usl
         row_in_dataframe += 1
         usl = ''
         y = 0
    dfwrite('Комментарий')  
   # Обрабатываем пустые строки
elif i.strip('\n') == '':
     continue 

Python обладает четкой структурой, поэтому, каждая строка проверяется на условия:

# Обрабатываем переменные
elif ('=' in i) and (('if ' or 'else' or 'elif ') not in i):
      y = 0
      p = 1
      per += i
      counterP=counter

      elif (p == 1) and (('if ' or 'else' or 'elif ') not in i):
           per += i

# Обрабатываем IF с условием в одну строку
elif (('if ' or 'else' or 'elif ') in i) and (':' in i):
      if per != '':
           perem()
      if ret != '':
           reter()
      dfwrite('Условие If')
      p = 0

Но если каждую строку просто записывать в DataFrame, то в итоговом результате получим «кашу».

Элементы часто занимают более одной строки, поэтому в коде предусмотрены флаги, для записи однотипных данных в одну запись. Например, когда подряд объявляются несколько переменных:

Отобранные данные записываются в DataFrame:

#Обработка фрагментов
def dfwrite(fragm):
    global row_in_dataframe, strategy, path, counter, i, df
    df.at[row_in_dataframe,'Стратегия']=strategy
    df.at[row_in_dataframe,'Путь']=path
    df.at[row_in_dataframe,'Номер строки фрагмента']=counter
    df.at[row_in_dataframe,'Тип фрагмента']=fragm
    df.at[row_in_dataframe,'Фрагмент']=i
    row_in_dataframe+=1
    pass

Полученный результат записываем в Excel или в csv:

#Параметры и формат сохранения
def save(df,xl,pthEnd):
    if xl == True:
        df.to_excel(os.path.join(pthEnd, "CodeMine_Result.xlsx"))
    elif xl == False:
        df.to_csv(os.path.join(pthEnd, "CodeMine_Result.csv"), encoding="windows-1251", sep="~") 

Для удобства работы добавим пользовательский интерфейс:

if __name__ == "__main__":
    root = Tk()
    root.geometry('600x400')
    var1 = BooleanVar()
    var1.set(False)
    var2 = BooleanVar()
    var2.set(False)

    lbl = Label(text="Задайте параметры")
    lbl.pack()

    frame1 = Frame(borderwidth=1, relief=SOLID)
    path_label = Label(frame1,text="Введите путь")
    path_label.pack(anchor=NW)

    path_entry = Entry(frame1, width=50)
    path_entry.pack(anchor=NW)

    open_button = Button(frame1,text="Открыть проводник", command=open_dir1)
    open_button.pack(anchor=NW)

    frame1.pack(anchor=NW, fill=X, padx=5, pady=5 )
Интерфейс
Интерфейс

Путь до обрабатываемых папок выбираем через проводник:

def open_dir1():
    global path_entry,filepath1
    path_entry.delete(0, END)
    filepath1 = filedialog.askdirectory()
    path_entry.insert(0,filepath1)  

А после выполнения программы предлагаем открыть результат:

# Сохраняем полученный DataFrame
save(df, xl, pthEnd)
resultMess = askyesno(title="Разбор выполнен успешно", message="Открыть полученный файл?")
if resultMess == True:
     if xl == True:
          os.startfile(os.path.join(pthEnd, "CodeMine_Result.xlsx"))
     else:
          os.startfile(os.path.join(pthEnd, "CodeMine_Result.csv")) 
Сообщение после обработки
Сообщение после обработки

Давайте рассмотрим применение программы на примере:

Пример разбираемого кода
Пример разбираемого кода

Результатом разбора данного фрагмента будет excel файл:

Результат разбора
Результат разбора

На рисунке выше можно увидеть, какие переменные используются при работе и как они преобразовываются. А за счет фильтров можно отобрать только необходимую в данный момент информацию:

Фильтр по переменной Age
Фильтр по переменной Age

Вывод

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

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

Но уже сейчас, можно дать ответ на вопрос из темы поста. Да, аналитики могут читать код. И основа, заложенная в тему данного поста, является тому подтверждением.

Теги:
Хабы:
Всего голосов 4: ↑1 и ↓30
Комментарии2

Публикации

Работа

Data Scientist
39 вакансий

Ближайшие события