<jupyter_start><jupyter_text>База с разметкой<jupyter_code>import pandas as pd
data = pd.DataFrame()

for i in range(1, 7):
    data_part = pd.read_excel(f'women_cases_part_{i}.xlsx')
    data = pd.concat([data, data_part])

data = data[['ID', 'Статья УК РФ', 'text', 'ДН']].dropna(subset=['ДН', 'text']).drop_duplicates('ID').set_index('ID')
data.head()
data['n_articles'] = data['Статья УК РФ'].apply(lambda x: len(x.split(',')))
data['art_105'] = data['Статья УК РФ'].str.contains('105').astype(int)
data['art_107'] = data['Статья УК РФ'].str.contains('107').astype(int)
data['art_111'] = data['Статья УК РФ'].str.contains('111 Часть 4').astype(int)
data.head()
len(data)
data['ДН'].value_counts(normalize=True)
data[data['ДН']<98]['ДН'].value_counts(normalize=True)<jupyter_output><empty_output><jupyter_text>Проверяем дела, ошибочно определённые как "женские"<jupyter_code>import re
patterns = [
    r'скончалась',
    r'погибш[аеу][йяю]',
    r'смерт[иь]ю? потерпевшей',
    r'смерт[иь]ю? последней',
    r'мертва',
    r'умерла',
    r'е[её] труп',
    r'труп женщины',
    r'оказывала сопротивлени',
    r'изби[лть]+ е[её]',
    r'е[её] изби[лть]+',
    r'уби[лть]+ е[её]',
    r'е[её] уби[лть]+',
    r'нан[её]с ей [<\d>]+? удар'
]

def check_patterns(text):
    global patterns
    
    for pattern in patterns:
        if re.search(pattern, text):
            return True
    return False

def define_pattern(text):
    global patterns
    
    for pattern in patterns:
        if re.search(pattern, text):
            return pattern
    return None
# приняли решение убрать из ключевых слов первые 6 выражений, кроме "её труп"
data[data['ДН']==99]['text'].apply(define_pattern).value_counts()
for text in data[(data['ДН']==99)&(data['text'].str.lower().str.contains('умерла'))]['text'][:7]:
    print(text)<jupyter_output>П Р И Г О В О Р
ИМЕНЕМ РОССИЙСКОЙ ФЕДЕРАЦИИ
Дело № 1-17/2018                             15 марта 2018 года 
Пушкинский районный суд Санкт-Петербурга в составе 
председательствующего судьи Макаровой Т.Г.,
при секретарях Стафеевой Ю.В., Белоусе А.О.,
с участием помощников прокурора Пушкинского района Санкт-Петербурга Коломийца В.В., Пройдаковой А.В., Серобяна А.В., Смирновой О.О., прокурора Пушкинского района Санкт-Петербурга Никитиной И.Н.,
потерпевшего П,
подсудимого Никифорова Д.В., 
защитника адвоката Абакумовой Т.И., представившей удостоверение № 1922 и ордер Н 099408 от 12.10.2017 года,
рассмотрев материалы уголовного дела в отношении: 
Никифоров Д.В. , ..., ранее судимого:
- 24.04.2009 года Лужским городским судом Ленинградской области по ч. 3 ст. 30 ч. 2 ст. 167, ч. 1 ст. 105, ч. 4 ст. 111 УК РФ на основании ч. 3 ст. 69 УК РФ к 12 годам лишения свободы, с отбыванием наказания в исправительной колонии строгого режима, постановлением Тосненского городского суда Ленинградской облас[...]<jupyter_text>Предобрабатываем текстовые данные для модели<jupyter_code>data = data[data['ДН'] < 98]
data['text_prep'] = data['text'].str.lower()
data.head()
def keep_only_rus(text):    
    new_text = ''
    for symbol in text:
        if re.match(r'[А-я]', symbol) or symbol == ' ':
            new_text += symbol
        else:
            new_text += ' '
    return new_text
data['text_prep'] = data['text_prep'].apply(keep_only_rus)
data.head()
def del_double_spaces(text_with_double_spaces):
    while '  ' in text_with_double_spaces:
        text_with_double_spaces = text_with_double_spaces.replace('  ',' ')
    return text_with_double_spaces
data['text_prep'] = data['text_prep'].apply(del_double_spaces)
data.head()
import pymystem3
mstem = pymystem3.Mystem()

def lemmatize(raw_text):
    return ''.join(mstem.lemmatize(raw_text)).strip()
data['text_prep'] = data['text_prep'].apply(lemmatize)
data.head()
import stop_words

stopwords = stop_words.get_stop_words('russian')
stopwords.extend(stop_words.get_stop_words('english'))
stopwords = list(set(stopwords))
stopwords += [
    'фио', 'гггг', 'подсудимый', 'суд',
    'изымать', 'согласно', 'наказание',
    'потерпевший', 'показание', 'судебный',
    'преступление', 'адрес', 'свидетель',
    'свой', 'находиться', 'час', 'ход'
             ]

def del_stopwords(text):
    global stopwords
    new_text = []
    for word in text.split():
        if word not in stopwords and len(word) > 2:
            new_text.append(word)
    return ' '.join(new_text)
data['text_prep'] = data['text_prep'].apply(del_stopwords)
data.head()
data['text_prep'] = data['text_prep'].apply(del_double_spaces)
data.head()
from sklearn.feature_extraction.text import CountVectorizer
cvect = CountVectorizer(min_df=0.05).fit(data['text_prep'])
matrix = cvect.transform(data['text_prep'])
td_matrix = pd.DataFrame(matrix.toarray(), index=data.index, columns=cvect.get_feature_names())
td_matrix.head()
td_matrix.sum().sort_values(ascending=False)[:30]
td_matrix['VIOLENCE'] = data['ДН']
td_matrix['N_ARTICLES'] = data['n_articles']
td_matrix['A_105'] = data['art_105']
td_matrix['A_107'] = data['art_107']
td_matrix['A_111'] = data['art_111']
td_matrix
y = td_matrix['VIOLENCE']
X = td_matrix.drop("VIOLENCE", axis=1)
y.shape, X.shape
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=4)
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier(n_estimators=15, min_samples_leaf=5, min_samples_split=5, random_state=4)
rfc.fit(X_train, y_train)
from sklearn.metrics import classification_report
print(classification_report(y_train, rfc.predict(X_train)))
print(classification_report(y_test, rfc.predict(X_test)))
import numpy as np
import operator
feat_indexes = np.argsort(rfc.feature_importances_)[::-1]
feat_words = {v:k for k, v in cvect.vocabulary_.items()}
[print(feat_words[i]) for i in feat_indexes[:17]];
from sklearn.ensemble import GradientBoostingClassifier
gbc = GradientBoostingClassifier(max_depth=3, n_estimators=50, random_state=4)
gbc.fit(X_train, y_train)
print(classification_report(y_train, gbc.predict(X_train)))
print(classification_report(y_test, gbc.predict(X_test)))
feat_indexes = np.argsort(gbc.feature_importances_)[::-1]
feat_words = {v:k for k, v in cvect.vocabulary_.items()}
[print(feat_words[i]) for i in feat_indexes[:17]];
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(random_state=0, max_iter=10000)
lr.fit(X_train, y_train)
print(classification_report(y_train, lr.predict(X_train)))
print(classification_report(y_test, lr.predict(X_test)))
pd.DataFrame(zip(list(X.columns), list(lr.coef_[0])), columns=['word', 'coef']).sort_values('coef', ascending=False)[:30]
pd.DataFrame(zip(list(X.columns), list(lr.coef_[0])), columns=['word', 'coef']).sort_values('coef', ascending=True)[:30]<jupyter_output><empty_output><jupyter_text>Полная база текстов, предсказание неразмеченных кейсов<jupyter_code>full = pd.read_excel('women_cases_ALL.xlsx')[['ID', 'Статья УК РФ', 'text']].set_index('ID')
full['n_articles'] = full['Статья УК РФ'].apply(lambda x: len(x.split(',')))
full['art_105'] = full['Статья УК РФ'].str.contains('105').astype(int)
full['art_107'] = full['Статья УК РФ'].str.contains('107').astype(int)
full['art_111'] = full['Статья УК РФ'].str.contains('111 Часть 4').astype(int)
full.head()
full['text_prep'] = full['text'].str.lower()
full['text_prep'] = full['text_prep'].apply(keep_only_rus)
full['text_prep'] = full['text_prep'].apply(del_double_spaces)
full['text_prep'] = full['text_prep'].apply(lemmatize)
full['text_prep'] = full['text_prep'].apply(del_stopwords)
full['text_prep'] = full['text_prep'].apply(del_double_spaces)
full.head()
full_matrix = cvect.transform(full['text_prep'])
full_td_matrix = pd.DataFrame(full_matrix.toarray(), index=full.index, columns=cvect.get_feature_names())
full_td_matrix.shape
full_td_matrix['N_ARTICLES'] = full['n_articles']
full_td_matrix['A_105'] = full['art_105']
full_td_matrix['A_107'] = full['art_107']
full_td_matrix['A_111'] = full['art_111']
full_td_matrix.shape
predictions = pd.DataFrame(gbc.predict(full_td_matrix), index=full_td_matrix.index, columns=['prediction'])
predictions['probability_0'] = gbc.predict_proba(full_td_matrix)[:, 0]
predictions['probability_1'] = gbc.predict_proba(full_td_matrix)[:, 1]
predictions
predictions['prediction'].sum()*0.81 / len(predictions)
predictions['prediction'].sum()*0.81 
predictions.sum()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15866015019668614, 'fraction_numerical': 0.023125521516271307, 'mean_word_length': 6.044500419815281, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '237710', 'license': 'MIT', 'n_tokens_mistral': 3461, 'n_tokens_neox': 3498, 'n_words': 582, 'path': 'femicide_TEXT_ANALYSIS.ipynb', 'repo_name': 'afokin52/algorithm_sveta', 'size': '8389'}