Git Product home page Git Product logo

Comments (5)

bab2min avatar bab2min commented on August 22, 2024 1

분석결과는 Kiwi::analyzeSent 함수의 다음 부분에서 생성된다.

Kiwi/src/Kiwi.cpp

Lines 539 to 599 in ebd7ba8

Vector<std::pair<PathEvaluator::Path, float>> res;
//auto h = langMdl->getHeader();
switch (langMdl->getHeader().key_size)
{
case 1:
res = PathEvaluator::findBestPath<uint8_t>(this, nodes, topN);
break;
case 2:
res = PathEvaluator::findBestPath<uint16_t>(this, nodes, topN);
break;
case 4:
res = PathEvaluator::findBestPath<uint32_t>(this, nodes, topN);
break;
case 8:
res = PathEvaluator::findBestPath<uint64_t>(this, nodes, topN);
break;
default:
throw runtime_error{ "wrong langMdl" };
}
for (auto&& r : res)
{
vector<TokenInfo> rarr;
const KString* prevMorph = nullptr;
for (auto&& s : r.first)
{
if (!get<1>(s).empty() && get<1>(s)[0] == ' ') continue;
u16string joined;
do
{
if (!integrateAllomorph)
{
if (POSTag::ep <= get<0>(s)->tag && get<0>(s)->tag <= POSTag::etm)
{
if ((*get<0>(s)->kform)[0] == u'')
{
if (prevMorph && prevMorph[0].back() == u'')
{
joined = joinHangul(u"" + get<0>(s)->kform->substr(1));
break;
}
else if (FeatureTestor::isMatched(prevMorph, CondPolarity::positive))
{
joined = joinHangul(u"" + get<0>(s)->kform->substr(1));
break;
}
}
}
}
joined = joinHangul(get<1>(s).empty() ? *get<0>(s)->kform : get<1>(s));
} while (0);
rarr.emplace_back(joined, get<0>(s)->tag);
rarr.back().morph = get<0>(s);
size_t nlen = (get<1>(s).empty() ? *get<0>(s)->kform : get<1>(s)).size();
size_t nlast = get<2>(s);
size_t nllast = min(max(nlast, nlen) - nlen, posMap.size() - 1);
rarr.back().position = posMap[nllast];
rarr.back().length = posMap[min(nlast, posMap.size() - 1)] - posMap[nllast];
prevMorph = get<0>(s)->kform;
}
ret.emplace_back(rarr, r.second);
}

여기서 PathEvaluator::Path는 다음과 같이 정의됨:

using Path = Vector<std::tuple<const Morpheme*, KString, uint32_t>>;

get<0>(s)const Morpheme*(형태소를 가리키는 포인터. OOV일 경우 nullptr), get<1>(s)KString(형태. OOV의 경우에만 값이 들어감), get<2>(s)uint32_t(형태소의 끝지점 위치. UTF16 문자단위)를 뜻한다.
이전 형태소의 품사태그가 NNG나 XR이고 현재 형태소의 품사 태그가 XSV인 경우는 VV로 합쳐주는 식으로 로직을 추가하면 해결 가능. 반복문 내에 모든 규칙을 추가하여 다루기는 복잡할 것이므로 다음과 같이 함수를 추가하면 좀 더 구현하기 용이할듯.

using MorphInfo = std::tuple<const Morpheme*, KString, uint32_t>;

bool concatMorphemes(const MorphInfo& prev, const MorphInfo& current, MorphInfo& out);
/*
prev: 이전 형태소의 정보
current: 현재 형태소의 정보
out: 합쳐진 형태소의 정보

return 값: 합치기가 수행된 경우 out에 결과를 쓰고 true를 반환. 그 외에는 false를 반환.
*/

from kiwi.

bab2min avatar bab2min commented on August 22, 2024

접두사/접미사가 분리된 명사를 통합하는 기능도 있으면 좋을듯.

XPN + NN. + XSN => NN.
XPN + NN. => NN.
NN. + XSN => NN.

from kiwi.

emiatej9 avatar emiatej9 commented on August 22, 2024

@bab2min

혹시 처음부터 옵션에 따라서 바로 사랑하다사랑하/VV + 다/EF로 갈 수는 없을까요.
사랑/NNG + 하/XSV + 다/EF로 우선 분리한 다음에 사랑하/VV + 다/EF로 갈 수 밖에 없는 건가요?

사랑하다 같은 경우 사랑/NNG + 하/XSV + 다/EF와 같이 분석되는데
종종 동사/형용사의 경우 어근을 분리하지 않고 전체형인 사랑하/VV + 다/EF와 같이 분석하는게 용이할 때도 있음.

from kiwi.

bab2min avatar bab2min commented on August 22, 2024

@emiatej9
네 그것 역시 가능한 방법이고 확률적으로 더 올바른 결과를 낼 것으로 예상되지만, 그렇게 하려면 동사/형용사 어근이 결합된 경우의 언어 모델을 별도로 가지고 있어야합니다.

구체적으로 먼저 언어 모델에 사랑하/VV와 같은 어휘들이 포함되어 있어야하고, 사랑하/VV 다음에는 다/EF와 같은 형태소가 등장한다는 확률정보도 포함되어 있어야합니다. 그러나 현재 언어모델에는 사랑/NNG, 하/XSV만 어휘만 포함되어 있고, 사랑하/VV는 어휘에 없는 상황이거든요. 당연히 사랑하/VV 다음에 등장하는 형태소들에 대한 확률정보도 없구요.

학습데이터로부터 사랑하/VV 처럼 동사/형용사 어근이 결합된 형태로 언어모델을 만들 수 있지만, 그 경우 배포시에 두 벌의 언어 모델을 포함해야해서 현재로써는 조금 부담스러운 선택일수밖에 없습니다. 따라서 궁여지책으로 분석 후에 후처리로 재결합하는 방식을 일단 구현해보고자 계획 중입니다.

글을 작성중에 막 떠오른 생각인데, 장기적으로는 여러 종류의 형태소 분석용 언어 모델을 빌드해서 제공하고, 유저는 자신의 상황에 맞춰 선택하여 분석기를 돌릴 수 있는 방향으로 나아가면 좋을 것 같다는 생각이 드네요.

from kiwi.

bab2min avatar bab2min commented on August 22, 2024

해당 기능은 0.11.0 버전에서 후처리 로직으로 추가되었고, 이 기능을 켜기 위한 Match::join* 계열 열거형이 추가되었습니다.
테스트 코드는 아래와 같습니다.

Kiwi/test/test_cpp.cpp

Lines 325 to 344 in 380ccd4

TEST(KiwiCpp, JoinAffix)
{
Kiwi& kiwi = reuseKiwiInstance();
auto sample = u"사랑스러운 풋사과들아! 배송됐니";
auto ores = kiwi.analyze(sample, Match::none);
auto res0 = kiwi.analyze(sample, Match::joinNounPrefix);
EXPECT_EQ(res0.first[3].str, u"풋사과");
auto res1 = kiwi.analyze(sample, Match::joinNounSuffix);
EXPECT_EQ(res1.first[4].str, u"사과들");
auto res2 = kiwi.analyze(sample, Match::joinNounPrefix | Match::joinNounSuffix);
EXPECT_EQ(res2.first[3].str, u"풋사과들");
auto res3 = kiwi.analyze(sample, Match::joinAdjSuffix);
EXPECT_EQ(res3.first[0].str, u"사랑스럽");
auto res4 = kiwi.analyze(sample, Match::joinVerbSuffix);
EXPECT_EQ(res4.first[8].str, u"배송되");
auto res5 = kiwi.analyze(sample, Match::joinAffix);
EXPECT_EQ(res5.first[0].str, u"사랑스럽");
EXPECT_EQ(res5.first[2].str, u"풋사과들");
EXPECT_EQ(res5.first[5].str, u"배송되");
}

from kiwi.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.