forked from rickiepark/ml-powered-applications
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdata_processing.py
173 lines (147 loc) · 5.64 KB
/
data_processing.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split, GroupShuffleSplit
from scipy.sparse import vstack, hstack
def format_raw_df(df):
"""
데이터를 정제하고 질문과 대답을 합칩니다.
:param df: 원본 DataFrame
:return: 처리된 DataFrame
"""
# 타입을 고치고 인덱스를 설정합니다.
df["PostTypeId"] = df["PostTypeId"].astype(int)
df["Id"] = df["Id"].astype(int)
df["AnswerCount"] = df["AnswerCount"].fillna(-1)
df["AnswerCount"] = df["AnswerCount"].astype(int)
df["OwnerUserId"].fillna(-1, inplace=True)
df["OwnerUserId"] = df["OwnerUserId"].astype(int)
df.set_index("Id", inplace=True, drop=False)
df["is_question"] = df["PostTypeId"] == 1
# 문서화된 것 이외의 PostTypeId를 필터링합니다.
df = df[df["PostTypeId"].isin([1, 2])]
# 질문과 대답을 연결합니다.
df = df.join(
df[["Id", "Title", "body_text", "Score", "AcceptedAnswerId"]],
on="ParentId",
how="left",
rsuffix="_question",
)
return df
def train_vectorizer(df):
"""
벡터화 객체를 훈련합니다.
훈련 데이터와 그 외 데이터를 변환하는데 사용할 벡터화 객체를 반환합니다.
:param df: 벡터화 객체를 훈련하는데 사용할 데이터
:return: 훈련된 벡터화 객체
"""
vectorizer = TfidfVectorizer(
strip_accents="ascii", min_df=5, max_df=0.5, max_features=10000
)
vectorizer.fit(df["full_text"].copy())
return vectorizer
def get_vectorized_series(text_series, vectorizer):
"""
사전 훈련된 벡터화 객체를 사용해 입력 시리즈를 벡터화합니다.
:param text_series: 텍스트의 판다스 시리즈
:param vectorizer: 사전 훈련된 sklearn의 벡터화 객체
:return: 벡터화된 특성 배열
"""
vectors = vectorizer.transform(text_series)
vectorized_series = [vectors[i] for i in range(vectors.shape[0])]
return vectorized_series
def add_text_features_to_df(df):
"""
DataFrame에 특성을 추가합니다.
:param df: DataFrame
:return: 특성이 추가된 DataFrame
"""
df["full_text"] = df["Title"].str.cat(df["body_text"], sep=" ", na_rep="")
df = add_v1_features(df.copy())
return df
def add_v1_features(df):
"""
입력 DataFrame에 첫 번째 특성을 추가합니다.
:param df: 질문 DataFrame
:return: 특성이 추가된 DataFrame
"""
df["action_verb_full"] = (
df["full_text"].str.contains("can", regex=False)
| df["full_text"].str.contains("What", regex=False)
| df["full_text"].str.contains("should", regex=False)
)
df["language_question"] = (
df["full_text"].str.contains("punctuate", regex=False)
| df["full_text"].str.contains("capitalize", regex=False)
| df["full_text"].str.contains("abbreviate", regex=False)
)
df["question_mark_full"] = df["full_text"].str.contains("?", regex=False)
df["text_len"] = df["full_text"].str.len()
return df
def get_vectorized_inputs_and_label(df):
"""
DataFrame 특성과 텍스트 벡터를 연결합니다.
:param df: 계산된 특성의 DataFrame
:return: 특성과 텍스트로 구성된 벡터
"""
vectorized_features = np.append(
np.vstack(df["vectors"]),
df[
[
"action_verb_full",
"question_mark_full",
"norm_text_len",
"language_question",
]
],
1,
)
label = df["Score"] > df["Score"].median()
return vectorized_features, label
def get_feature_vector_and_label(df, feature_names):
"""
벡터 특성과 다른 특성을 사용해 입력과 출력 벡터를 만듭니다.
:param df: 입력 데이터프레임
:param feature_names: (‘vectors’ 열을 제외한) 특성 열 이름
:return: 특성 배열과 레이블 배열
"""
vec_features = vstack(df["vectors"])
num_features = df[feature_names].astype(float)
features = hstack([vec_features, num_features])
labels = df["Score"] > df["Score"].median()
return features, labels
def get_normalized_series(df, col):
"""
DataFrame 열을 정규화합니다.
:param df: DataFrame
:param col: 열 이름
:return: Z-점수를 사용해 정규화된 시리즈 객체
"""
return (df[col] - df[col].mean()) / df[col].std()
def get_random_train_test_split(posts, test_size=0.3, random_state=40):
"""
DataFrame을 훈련/테스트 세트로 나눕니다.
DataFrame이 질문마다 하나의 행을 가진다고 가정합니다.
:param posts: 모든 포스트와 레이블
:param test_size: 테스트 세트로 할당할 비율
:param random_state: 랜덤 시드
"""
return train_test_split(
posts, test_size=test_size, random_state=random_state
)
def get_split_by_author(
posts, author_id_column="OwnerUserId", test_size=0.3, random_state=40
):
"""
훈련 세트와 테스트 세트로 나눕니다.
작성자가 두 세트 중에 하나에만 등장하는 것을 보장합니다.
:param posts: 모든 포스트와 레이블
:param author_id_column: author_id가 들어 있는 열 이름
:param test_size: 테스트 세트로 할당할 비율
:param random_state: 랜덤 시드
"""
splitter = GroupShuffleSplit(
n_splits=1, test_size=test_size, random_state=random_state
)
splits = splitter.split(posts, groups=posts[author_id_column])
train_idx, test_idx = next(splits)
return posts.iloc[train_idx, :], posts.iloc[test_idx, :]