Joonas' Note
노래 가사의 반복도를 계산할 수 있을까? 본문
배경
수 많은 노래들이 있었다. 그 중에서 가장 중독적인 노래는 무엇이었을까.
아마도 후크송이 뽑히지 않을까싶은데, 그 이유는 가사 반복이 많은 이유라고 추측한다.
그렇다면 노래의 "중독성", 엄밀히는 "가사가 반복된 정도"를 어떻게 수치로 계산할 수 있을까? 라는 고민에서 출발한 글이다.
정의부터 모호한 문제이지만 한번 계산해보고자 하던 여러 시도를 글로 남겨보고 납득할 수 있는 지 결과도 함께 기록한다.
단순하게 빈도 세기
처음에는 단순하게 노래마다 (공백으로 구분된) 동일한 구절이 반복되는 횟수를 세고, 가장 많이 반복된 횟수가 높은 노래가 더 반복을 많이 하는 노래라고 생각했다.
공백 단위로 구분한 이유는, 문장 단위로 자르기에는 "La La La" 와 "La La La La" 가 서로 다르게 세어지는 것을 원치 않아서이다.
그런데 이렇게 계산하면 가사가 길수록 반복도가 높게 나오는 문제가 있다.
예를 들면, 애국가는 4절까지 있고 후렴이 매 절마다 있기 때문에 후렴구의 비율만 보면 노래의 50% 이다.
하지만 최대 4번 등장하기 때문에 낮은 빈도수로 계산된다.
가사 대비 단어 비율?
그럼 가사 대비 빈도수(비율)로 계산하면 해결되느냐?
아니다. 오히려 반대의 상황이 펼쳐진다.
오히려 과거에는 가사가 짧았기 때문에 비율이 더 높게 나오게 된다.
따라서 가사 내 단어의 출현 빈도만 가지고는 반복한 정도를 측정하기 어렵겠다고 생각했다.
단어의 등장 확률 기반
반복된다는 것의 의미를 다시금 생각해보았다. 반복된다는 것은 앞에서 등장한 단어가 뒤에 다시 등장한다는 의미인데, 그런 단어가 많을수록 노래가 더욱 반복된다고 느낄 것이다.
그렇다면 단어의 등장 확률로 생각해볼 수 있고, "가사 전체에서, 서로 다른 위치의 어떤 두 단어를 골랐을 때, 그 단어가 같을 확률"을 구하기로 했다.
즉, 가사에 등장한 단어 집합을 \(W\), 단어 \(w\)가 등장한 횟수를 \(F_w\) 라고 했을때, 어떤 단어가 중복될 확률을 아래와 같이 계산했다.
\( \frac{F_{w_i}}{|W|} \times \frac{F_{w_i}-1}{|W|-1} \)
하지만 이 방법은 비율로 계산하는 것보다 더 심한 양상을 보였다.
뇌피셜 수식
단어의 등장 확률 기반으로 판단할 수 있을 것 같은데 뭔가 아쉬웠다. 그래서 수식을 조금 바꿔보았다.
위 수식에서는 여전히 단어 집합의 크기와 상관없이 비중만 보고 있으므로, 단어 집합이 작을수록 확률이 더 높을 것이다.
그래서 단어 집합의 크기를 곱해줘서 각 단어의 확률의 가중치를 비슷하게 맞출 수 있지 않을까 생각했다.
\( \frac{F_{w_i}}{|W|} \times \frac{F_{w_i}-1}{|W|-1} \times |W| \)
이렇게 계산했더니 가사 반복도 TOP 15 목록이 아래와 같이 나왔다.
1위가 미스터 - 카라 (2009) 이고, 2위는 아리송해 - 이은하 (1979), 그리고 3위로는 Tell me - 원더걸스 (2007) 인데, 가사를 직접 보면... 가사 반복이 굉장히 많은 곡들이다.
그 뒤로 이어지는 노래들도 어느 정도 납득이 되기는 하지만, 수식이 검증된 게 아니라서 찝찝한 채로 남겼다.
참고로 시대별 랭킹은 아래와 같이 나왔다.
TF-IDF 지표 계산
TF-IDF는 문서 내 단어의 빈도를 기반으로 중요도를 분석하는 지표이다.
보통은 문서에서 핵심 키워드를 추출하려고 할 때 사용하는데, TF(Term Frequency) 개념부터 특정 단어가 문서 내에 얼마나 자주 등장하는 지를 의미하기 때문에 TF-IDF 지표를 사용하여 가사의 반복도를 측정해보고자 했다.
한 노래의 가사 전체를 하나의 문서로 보고, 해당 문서 안에서 각 단어들이 얼마나 중요한 지 계산하는 방식이다.
노래 전체를 공백으로 구분해서 ["동해물과", "백두산이", "마르고", "닳도록", ...] 과 같이 말뭉치(corpus)를 만들고, 아래와 같이 계산한다.
def get_tfidf_matrix(corpus: list) -> scipy.sparse._csr.csr_matrix:
tfidfv = TfidfVectorizer().fit(corpus)
return tfidfv.transform(corpus)
def get_tfidf_mean(corpus: list) -> np.ndarray:
return np.array(get_tfidf_matrix(corpus).mean(axis=0)).flatten()
# TF-IDF 값이 0 인 값은 제외하고 계산해보기
def get_tfidf_mean_nonzero(corpus: list) -> np.ndarray:
mat = get_tfidf_matrix(corpus)
return np.array([m.sum() / m.count_nonzero() for m in mat.transpose()])
연도별로 각 노래들의 평균 TF-IDF 값을 계산했을 때 결과는 아래와 같다.
TF-IDF 값의 평균이 가장 높은 노래는 사랑의 모닥불 - 이용복 (1974) 인데, 그 외에도 대부분이 1970~80년대 노래이다.
참고로 위 랭킹에서 2위인 먼데서 오신 손님 - 조미미 (1971) 의 가사는 아래와 같다.
오랜만에 오셨습니다 오랜만에 만났습니다
그렇게 기다려도 오지 않던 임인데
꿈속에서 그린 임인데
어이 하라고 어이 하라고 나는나는 어이 하라고
대답해 주세요 말 좀 하세요
무어라고 말하리까 무어라고 말하리까
먼 데서 오신 손님
오랜만에 오셨습니다 오랜만에 만났습니다
이렇게 애타도록 기다리던 임인데
마음속에 그린 임인데
어이 하라고 어이 하라고 이제와서 어이 하라고
대답해 주세요 말 좀 하세요
무어라고 부르리까 무어라고 부르리까
먼 데서 오신 손님
이렇게 가사를 확인해보니, 문장이나 문단 단위의 반복은 TF-IDF 지표가 더 잘 드러나는 것 같다.
상관 계수 확인하기
상관 계수가 0 일수록, 즉, 아래 그림에서 색깔이 옅을수록 행/열 항목은 서로 관계가 없다는 뜻이다.
기준이 될 수 있는 지표는 가사 길이(length)라고 생각하고 비교해봤는데,
단어의 등장 확률 + 수정 버전으로 계산한 방법과 TF-IDF 에서 0 을 제외한 평균이 가사 길이에 영향을 받지 않는 것으로 나왔다.
참고
'알고리즘' 카테고리의 다른 글
[코딩으로 풀어보기] 문제적 남자 4화 - (9, 9, 9, 9, 9, 9)으로 100 만들기 (0) | 2022.05.20 |
---|---|
[Graphics/Math] Euler to Quaternion, Quaternion to Euler (0) | 2022.04.05 |
[코딩으로 풀어보기] 자동차 번호판의 숫자가 겹칠 확률 (0) | 2021.11.12 |
트리의 노드 순서 정리해서 구간으로 만들기 (0) | 2020.05.13 |
Binary search 쉬운 구현 + 설명 (0) | 2020.04.06 |