Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

write test cases as detailed in here #51

Closed
Tracked by #15
eubinecto opened this issue May 4, 2022 · 4 comments
Closed
Tracked by #15

write test cases as detailed in here #51

eubinecto opened this issue May 4, 2022 · 4 comments

Comments

@eubinecto
Copy link
Owner

No description provided.

@eubinecto eubinecto mentioned this issue May 4, 2022
53 tasks
@eubinecto
Copy link
Owner Author

eubinecto commented May 4, 2022

1 -> 2, 3
2 -> 3
으로 가는 것은 허용하지만,
3 -> 1, 2는 허용하지 않는 편이 개발이 더 편할 것 같다.

왜? 예를 들면 이런 예시를 일일히 수작업으로 고쳐야 한다:

main_test.py::TestStyler::test_irregular_conjugation_bieup_harmonious_with_syllables 2022-05-04 15:00:28.485 INFO    root: khaiii opened with rsc_dir: "/Users/eubinecto/Projects/Big/politely/venv/lib/python3.8/site-packages/khaiii/share/khaiii", opt_str: ""
FAILED [100%]l_last = ['ㄱ', 'ㅗ', 'ㅂ']
r_first = ['ㅇ', 'ㅏ', ' ']
ㅂ 불규칙: 고와요
l_last = ['ㄱ', 'ㅗ', 'ㅂ']
r_first = ['ㅇ', 'ㅏ', ' ']
ㅂ 불규칙: 고와
l_last = ['ㄱ', 'ㅗ', 'ㅂ']
r_first = ['ㅇ', 'ㅓ', ' ']
ㅂ 불규칙: 고워

main_test.py:195 (TestStyler.test_irregular_conjugation_bieup_harmonious_with_syllables)
'모래가 참 고워.' != '모래가 참 고와.'

Expected :'모래가 참 고와.'
Actual   :'모래가 참 고워.'
<Click to see difference>

self = <main_test.TestStyler testMethod=test_irregular_conjugation_bieup_harmonious_with_syllables>

    def test_irregular_conjugation_bieup_harmonious_with_syllables(self):
        """
        모음조화가 이루어진 ㅂ 불규칙
        """
        sent = "모래가 참 고와."
        self.assertEqual("모래가 참 고와.", self.styler(sent, self.ban[0], self.ban[1]))  # noqa
        self.assertEqual("모래가 참 고와요.", self.styler(sent, self.jon[0], self.jon[1]))
        self.assertEqual("모래가 참 곱습니다.", self.styler(sent, self.formal[0], self.formal[1]))
        sent = "모래가 참 고와요."
        self.assertEqual("모래가 참 고와.", self.styler(sent, self.ban[0], self.ban[1]))  # noqa
        self.assertEqual("모래가 참 고와요.", self.styler(sent, self.jon[0], self.jon[1]))
        self.assertEqual("모래가 참 곱습니다.", self.styler(sent, self.formal[0], self.formal[1]))
        sent = "모래가 참 곱습니다."
>       self.assertEqual("모래가 참 고와.", self.styler(sent, self.ban[0], self.ban[1]))  # noqa

위가 무엇을 보여주는 것인가? 다음은 가능하다:

고와 -> 고와요 
고와 -> 곱습니다
고와요 -> 고와
고와요 -> 곱습니다

하지만 곱습니다 -> 고와는 불가능하다:

곱습니다  -> 고워

왜? 습니다의 경우 1, 2의 경우가 전부 또는 어요로 통일되기 때문이다. 원래의 어미가 무엇이었는지... 알길이 없다.
이건 어요도 마찬가지이지만, 위에서 볼 수 있듯 어요의 초성은 와 마찬가지로 모음이라, 1일 때의 어간활용을 어지간해서는 그대로 따라간다. 하지만 습니다의 초성은 자음이다. 그래서 위처럼 어간의 활용이 1, 2인 경우와 다를 수 밖에 없다.

어차피 반말부터 공부하는 외국인들은 숫자가 커지는 경우를 더 필요로 할것이기 때문에, politeness를 줄이는 알고리즘은 data augmentation의 용도가 아닌이상.. 굳이 필요없다.

그래서 우리는... 더이상 3 -> 1, 2는 지원하지 않겠다...! 그래야 개발에 속도가 붙을 것 같다.

@eubinecto
Copy link
Owner Author

eubinecto commented May 8, 2022

문제점

main_test.py:238: AssertionError
-------------------------------------------------------------------------- Captured stdout call --------------------------------------------------------------------------
l_last = ['ㅈ', 'ㅜ', 'ㅂ']
r_first = ['ㅇ', 'ㅓ', ' ']
ㅂ 불규칙: 주워요
======================================================================== short test summary info =========================================================================
FAILED main_test.py::TestStyler::test_irregular_jup - AssertionError: '저 쓰레기를 주웁시다.' != '저 쓰레기를 줍웁시다.'
    def test_irregular_jup(self):
        sent = "저 쓰레기를 줍자."
        self.assertEqual("저 쓰레기를 줍자.", self.styler(sent, self.ban[0], self.ban[1]))  # noqa
        self.assertEqual("저 쓰레기를 주워요.", self.styler(sent, self.jon[0], self.jon[1]))
        self.assertEqual("저 쓰레기를 주웁시다.", self.styler(sent, self.formal[0], self.formal[1]))

줍 + 어요 -> 주워요는 오케이.
하지만
줍 + ㅂ시다 -> 주웁시다는 not okay.

왜?

아.. if-else문의 반복이기에, 두개 이상의 케이스에 해당돼도 한 케이스만 적용하고 끝나버리기 때문인 것으로 보인다.

그렇다면 어떻게 해결할까?

if-else의 연속을 여러개의 if문의 나열로 바꿔야한다. 음.. 그게 말이 쉽지..ㅠㅠ

일단 방법을 한번 생각해보자. soynlp에서는 어떻게 하고 있지? 어떻게 여러개의 규칙을 적용하고 있을까?
분명 순서가 중요해질텐데...

    # ㄷ 불규칙 활용: 깨달 + 아 -> 깨달아
    if l_last[2] == 'ㄷ' and r_first[0] == 'ㅇ':
        l = stem[:-1] + compose(l_last[0], l_last[1], 'ㄹ')
        surface = l + ending
        candidates.add(surface)
        candidates.add(stem + ending) # 받 + 았다 -> 받았다
        if debug:
            print('ㄷ 불규칙: {}'.format(surface))

    # 르 불규칙 활용: 구르 + 어 -> 굴러
    if ( (l_last_ == '르' and stem[-2:] != '푸르') and
         (r_first_ == '아' or r_first_ == '어') and l_len >= 2 ):
        c0, c1, c2 = decompose(stem[-2])
        l = stem[:-2] + compose(c0, c1, 'ㄹ')
        r = compose('ㄹ', r_first[1], r_first[2]) + ending[1:]
        surface = l + r
        candidates.add(surface)
        if debug:
            print('르 불규칙: {}'.format(surface))

soynlp는 여러개가 순차적으로 적용되는 건 고려하지 않는다.
즉...
줍 + ㅂ시다 -> 줍웁시다 -> 주웁시다
이렇게 변화하는 과정은 고려하지 않고.
줍 + ㅂ시다 -> 줍웁시다 (1)
줍 + ㅂ시다 -> 주ㅂ시다 (2)

이렇게 두가지가 존재한다고 보는듯.
음... 나는 순서까지 고려를 해야할 것 같다. 이것에 대한 고민은 내일 이어서하기

오늘 뭐했음? - 정리

뭘했는지 쉽게 설명

어간의 활용 알고리즘을 수정하고 있다.
"줍 + ㅂ시다 -> 주웁시다"가 가능토록 하는게 목표인데. 현재 내 코드는
"줍 + ㅂ시다 -> 줍웁시다" 라고 출력한다.
즉 ㅂ탈락이 일어나야하는데 내 코드 상에서는 일어나지 않는다. 이 원인이 무엇인지 파악을 해야하는데, 시간상 일단 문제인식에 의의를 두고 내일로 넘기겠다!

@eubinecto
Copy link
Owner Author

eubinecto commented May 9, 2022

음... 일단 알고리즘 구현은 나중으로 미뤄보고.

지금은 애초에 계획했던 테스트만 쓰고 끝내자. TDD라고 생각하면 된다.
일단 failing test를 만들고, 나중에 하나씩 pass하도록 바꾸면 된다.

eubinecto added a commit that referenced this issue May 9, 2022
@eubinecto eubinecto mentioned this issue May 9, 2022
@eubinecto
Copy link
Owner Author

eubinecto commented May 9, 2022

오늘 뭐했지? 쉽게 설명

다음과 같이, soynlp에서 소개한 용언의 활용 케이스를
그대로 테스트에 옮겼다:

politely/main_test.py

Lines 247 to 336 in 6165ef1

def test_irregular_o(self):
"""
오 불규칙
"""
sent = "오늘 제주도로 여행왔어."
self.assertEqual("오늘 제주도로 여행왔어.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("오늘 제주도로 여행왔어요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("오늘 제주도로 여행왔습니다.", self.styler(sent, self.formal[0], self.formal[1]))
sent = "오늘 제주도로 여행왔어요."
self.assertEqual("오늘 제주도로 여행왔어.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("오늘 제주도로 여행왔어요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("오늘 제주도로 여행왔습니다.", self.styler(sent, self.formal[0], self.formal[1]))
def test_irregular_drop_ue(self):
"""
으 탈락 불규칙
"""
sent = "전등을 껐다."
self.assertEqual("전등을 껐다.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("전등을 껐어요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("전등을 껐습니다.", self.styler(sent, self.formal[0], self.formal[1]))
sent = "전등을 껐어요."
self.assertEqual("전등을 껐어.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("전등을 껐어요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("전등을 껐습니다.", self.styler(sent, self.formal[0], self.formal[1]))
def test_irregular_gara(self):
"""
-가라 불규칙
"""
sent = "저기로 가거라."
self.assertEqual("저기로 가거라.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("저기로 가세요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("저기로 가십시오.", self.styler(sent, self.formal[0], self.formal[1]))
sent = "저기로 가세요."
self.assertEqual("저기로 가.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("저기로 가세요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("저기로 가십시오.", self.styler(sent, self.formal[0], self.formal[1]))
def test_irregular_neura(self):
"""
-너라 불규칙
"""
sent = "이리 오너라."
self.assertEqual("이리 오너라.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("이리 오세요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("이리 오십시오.", self.styler(sent, self.formal[0], self.formal[1]))
sent = "이리 오세요."
self.assertEqual("이리 와.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("이리 오세요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("이리 오십시오.", self.styler(sent, self.formal[0], self.formal[1]))
def test_irregular_rue(self):
"""
-러 불규칙
"""
sent = "드디어 정상에 이르렀다."
self.assertEqual("드디어 정상에 이르렀다.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("드디어 정상에 이르렀어요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("드디어 정상에 이르렀습니다.", self.styler(sent, self.formal[0], self.formal[1]))
sent = "드디어 정상에 이르렀어요."
self.assertEqual("드디어 정상에 이르렀어.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("드디어 정상에 이르렀어요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("드디어 정상에 이르렀습니다.", self.styler(sent, self.formal[0], self.formal[1]))
def test_irregular_yue(self):
"""
-여 불규칙
"""
sent = "나는 그리하지 아니하였다."
self.assertEqual("나는 그리하지 아니하였다.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("저는 그리하지 아니하였어요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("저는 그리하지 아니하였습니다.", self.styler(sent, self.formal[0], self.formal[1]))
sent = "저는 그리하지 아니하였어요."
self.assertEqual("나는 그리하지 아니하였어.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("저는 그리하지 아니하였어요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("저는 그리하지 아니하였습니다.", self.styler(sent, self.formal[0], self.formal[1]))
def test_irregular_drop_hiut(self):
"""
ㅎ 탈락
"""
sent = "하늘이 파랗다."
self.assertEqual("하늘이 파랗다.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("하늘이 파래요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("하늘이 파랗습니다.", self.styler(sent, self.formal[0], self.formal[1]))
sent = "하늘이 파래요."
self.assertEqual("하늘이 파래.", self.styler(sent, self.ban[0], self.ban[1])) # noqa
self.assertEqual("하늘이 파래요.", self.styler(sent, self.jon[0], self.jon[1]))
self.assertEqual("하늘이 파랗습니다.", self.styler(sent, self.formal[0], self.formal[1]))

하나만 예를 들며 설명해보자면 이런걸 테스트하고 있다:

입력 = "하늘이 파랗다." 인 경우.

  • 반말로? 이미 반말이므로 "하늘이 파랗다"를 출력해야한다.
  • 존대로? -어요를 붙여서 "하늘이 파래요"를 출력해야한다. 파랗 + 어요의 과정에서 가 합쳐저 로 축약된다.
  • 극존대로? -습니다를 붙여서 "하늘이 파랗습니다"를 출력해야한다. 습니다는 모음으로 시작하는 것이 아니므로 ㅎ탈락이 일어나지 않는다.

저 테스트를 돌려보면 아직 완벽하지 않기 때문에 20개 중 8개는 패스하지 못한다. 하지만 개발을 시작하기전, 분명한 목표를 설정해둔다는 것에 오늘의 활동에 의의를 둔다.

... 그런데 이렇게 복잡한 한국어를 난 도대체 어떻게 하고 있는거지? 체득된 문법이란 참 신기한 것 같다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant