자바 알고리즘 의 코사인 싱크로 율 계산 문자열 싱크로 율

개술
기능 수요:최근 파충류 기술 을 통 해 각 관련 사이트 의 뉴스 를 찾 아 회사 데이터 에 저장 하고 있다.이 안 에는 네가 이미 기어 올 라 간 뉴스 와 비슷 한 뉴스 를 어떻게 보장 하 느 냐 하 는 기술 점 이 있다.
또는 같은 뉴스 는 데이터베이스 에 저장 되 지 않 습 니 다.다른 사이트 의 뉴스 를 인용 하거나 다른 사이트 의 뉴스 를 가 져 와 내용 을 조금 만 고치 면 자신의 사이트 에 올 리 기 때문이다.
해석 방안:최종 적 으로 코사인 싱크로 율 알고리즘 을 사용 하여 두 뉴스 본문의 싱크로 율 을 계산 하 는 것 이다.이제 스스로 블 로 그 를 써 서 정리 하 세 요.
이론 지식
먼저 블 로 그 를 추천 합 니 다.코사인 싱크로 율 알고리즘 에 대한 이론 이 비교적 명확 하고 우리 도 이 방식 에 따라 싱크로 율 을 계산 합 니 다.사이트 주소:싱크로 율 알고리즘 의 코사인 싱크로 율.
1.용건 만 말 하기
내 쪽 에 서 는 먼저 두 문자열 의 싱크로 율 을 계산 하 는 이론 지식 을 다시 한 번 정리한다.
(1)우선 벡터 를 통 해 인식도 공식 을 계산 하 는 것 을 알 아야 한다.

(2)알 겠 습 니 다.코사인 값 이 1 에 가 까 울 수록 두 개의 벡터 가 비슷 합 니 다.이것 을'코사인 유사 성'이 라 고 합 니 다.
코사인 값 이 0 에 가 까 울 수록 두 벡터 가 비슷 하지 않다 는 것 이다.즉,이 두 문자열 이 비슷 하지 않다 는 것 이다.
2.사례 이론 지식
예 를 들 어 상술 한 이론 으로 텍스트 의 유사 성 을 계산한다.간단 한 견 해 를 위해 서 먼저 문장 부터 시작 하 다.
문장 A:이 가죽 부츠 는 사이즈 가 커 요.그 번호 가 맞습니다.
문장 B:이 가죽 부츠 의 번 호 는 작 지 않 아 요.저것 이 더 잘 어 울 려 요.
어떻게 위의 두 말의 유사 도 를 계산 합 니까?
기본 적 인 사 고 는 이 두 마디 의 단어 가 비슷 할 수록 내용 이 비슷 해 야 한 다 는 것 이다.따라서 단어의 주파수 에 착안 하여 그것들의 유사 도 를 계산 할 수 있다.
첫걸음
문장 A:이/가죽 부츠/번호/커 요.저것/번호/적당 합 니 다.
문장 B:이/가죽 부츠/번호/아니오/작 습 니 다.
두 번 째 단 계 는 단어의 주파 수 를 계산한다.단어 마다 나타 나 는 빈도)
문장 A:이 부츠 는 1,가죽 부츠 1,번호 2,커 요.저것 은 1,적당 하 다 1,아니 0,작다 0,더 0.
문장 B:이 부츠 1,가죽 부츠 1,번호 1,0 이 커 요.그 마리 1,적당 하 다 1,아니 1,작다 1,더 1
세 번 째 단 계 는 단어의 주파수 벡터 를 쓴다.
문장 A:(1,1,2,1,1,0,0,0)
문장 B:(1,1,1,0,1,1,1,1,1)
네 번 째 단계:위의 공식 을 활용 하여 다음 과 같이 계산한다.

계산 결과 협각 의 코사인 수 치 는 0.81 로 1 에 매우 가 깝 기 때문에 위의 문장 A 와 문장 B 는 기본적으로 비슷 하 다.
2.실제 개발 사례
나 는 우리 의 실제 개발 과정 에서 문자열 유사 율 계산 코드 를 공유 했다.
1、pom.xml
주요 jar 가방 보 여주 기

<!--       -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.5</version>
</dependency>
<!--bean       -->
   <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!--    ,      -->
<dependency>
    <groupId>com.hankcs</groupId>
    <artifactId>hanlp</artifactId>
    <version>portable-1.6.5</version>
</dependency>
2.main 방법

/**
 *            
 */
public class Similarity {

    public static final  String content1="             ,            ,      ,      ";

    public static final  String content2="                ,          ,         ";


    public static void main(String[] args) {

        double  score=CosineSimilarity.getSimilarity(content1,content2);
        System.out.println("   :"+score);

        score=CosineSimilarity.getSimilarity(content1,content1);
        System.out.println("   :"+score);
    }
    
}
실행 결 과 를 먼저 봅 니 다:

실행 결 과 를 통 해 다음 과 같은 결 과 를 얻 을 수 있 습 니 다.
(1)첫 번 째 비교 유사 율 은 0.772853(이 두 문장 이 비슷 하 다 는 뜻)이 고 두 번 째 비교 유사 율 은 1.0(설명 이 똑같다)이다.
(2)우 리 는 이 문장의 분사 효 과 를 볼 수 있 고 그 다음은 품사 성 이다.
3.Tokenizer(단어 도구 클래스)

import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.seg.common.Term;
import java.util.List;
import java.util.stream.Collectors;


/**
 *        */
public class Tokenizer {

    /**
     *   */
    public static List<Word> segment(String sentence) {

        //1、   HanLP                 
        List<Term> termList = HanLP.segment(sentence);

        //                
        System.out.println(termList.toString());

        //2、     Word   (term.word        ,term.nature       )
        return termList.stream().map(term -> new Word(term.word, term.nature.toString())).collect(Collectors.toList());
    }
}
4.Word(봉 인 된 단어 결과)
이 안에 진정 으로 쓰 이 는 것 은 사실 단어 이름과 가중치 이다.

import lombok.Data;

import java.util.Objects;

/**
 *       */
@Data
public class Word implements Comparable {

    //   
    private String name;
    //   
    private String pos;

    //   ,       
    private Float weight;

    public Word(String name, String pos) {
        this.name = name;
        this.pos = pos;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(this.name);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Word other = (Word) obj;
        return Objects.equals(this.name, other.name);
    }

    @Override
    public String toString() {
        StringBuilder str = new StringBuilder();
        if (name != null) {
            str.append(name);
        }
        if (pos != null) {
            str.append("/").append(pos);
        }

        return str.toString();
    }

    @Override
    public int compareTo(Object o) {
        if (this == o) {
            return 0;
        }
        if (this.name == null) {
            return -1;
        }
        if (o == null) {
            return 1;
        }
        if (!(o instanceof Word)) {
            return 1;
        }
        String t = ((Word) o).getName();
        if (t == null) {
            return 1;
        }
        return this.name.compareTo(t);
    }
}
5.CosineSimilarity(유사 율 구체 적 실현 도구 류)

import com.jincou.algorithm.tokenizer.Tokenizer;
import com.jincou.algorithm.tokenizer.Word;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *     :     ,                              :   a=(x1,y1),  b=(x2,y2) similarity=a.b/|a|*|b| a.b=x1x2+y1y2
 * |a|=  [(x1)^2+(y1)^2],|b|=  [(x2)^2+(y2)^2]*/
public class CosineSimilarity {
    protected static final Logger LOGGER = LoggerFactory.getLogger(CosineSimilarity.class);

    /**
     * 1、           
     */
    public static double getSimilarity(String text1, String text2) {

        //  wei ,       0,       
        if (StringUtils.isBlank(text1) && StringUtils.isBlank(text2)) {
            return 1.0;
        }
        //     0   ,    ,        
        if (StringUtils.isBlank(text1) || StringUtils.isBlank(text2)) {
            return 0.0;
        }
        //                  1 (              ,      )
//        if (text1.equalsIgnoreCase(text2)) {
//            return 1.0;
//        }
        //   :    
        List<Word> words1 = Tokenizer.segment(text1);
        List<Word> words2 = Tokenizer.segment(text2);

        return getSimilarity(words1, words2);
    }

    /**
     * 2、                 
     */
    public static double getSimilarity(List<Word> words1, List<Word> words2) {

        double score = getSimilarityImpl(words1, words2);

        //(int) (score * 1000000 + 0.5)             ,  1034234.213       1034234。        0.5       
        score = (int) (score * 1000000 + 0.5) / (double) 1000000;

        return score;
    }

    /**
     *             :     ,                              :   a=(x1,y1),  b=(x2,y2) similarity=a.b/|a|*|b| a.b=x1x2+y1y2
     * |a|=  [(x1)^2+(y1)^2],|b|=  [(x2)^2+(y2)^2]
     */
    public static double getSimilarityImpl(List<Word> words1, List<Word> words2) {

        //     Word        weight(  )   
        taggingWeightByFrequency(words1, words2);

        //   :    
        //        Word       ,      map (key  ,value        (   ))
        Map<String, Float> weightMap1 = getFastSearchMap(words1);
        Map<String, Float> weightMap2 = getFastSearchMap(words2);

        //       set   
        Set<Word> words = new HashSet<>();
        words.addAll(words1);
        words.addAll(words2);

        AtomicFloat ab = new AtomicFloat();// a.b
        AtomicFloat aa = new AtomicFloat();// |a|   
        AtomicFloat bb = new AtomicFloat();// |b|   

        //    :      ,     
        words.parallelStream().forEach(word -> {
            //     a、b         
            Float x1 = weightMap1.get(word.getName());
            Float x2 = weightMap2.get(word.getName());
            if (x1 != null && x2 != null) {
                //x1x2
                float oneOfTheDimension = x1 * x2;
                //+
                ab.addAndGet(oneOfTheDimension);
            }
            if (x1 != null) {
                //(x1)^2
                float oneOfTheDimension = x1 * x1;
                //+
                aa.addAndGet(oneOfTheDimension);
            }
            if (x2 != null) {
                //(x2)^2
                float oneOfTheDimension = x2 * x2;
                //+
                bb.addAndGet(oneOfTheDimension);
            }
        });
        //|a|  aa  
        double aaa = Math.sqrt(aa.doubleValue());
        //|b|  bb  
        double bbb = Math.sqrt(bb.doubleValue());

        //  BigDecimal         
        //double aabb = aaa * bbb;
        BigDecimal aabb = BigDecimal.valueOf(aaa).multiply(BigDecimal.valueOf(bbb));

        //similarity=a.b/|a|*|b|
        //divide    :aabb   ,9        9 ,               
        double cos = BigDecimal.valueOf(ab.get()).divide(aabb, 9, BigDecimal.ROUND_HALF_UP).doubleValue();
        return cos;
    }


    /**
     *     Word        weight(  )   
     */
    protected static void taggingWeightByFrequency(List<Word> words1, List<Word> words2) {
        if (words1.get(0).getWeight() != null && words2.get(0).getWeight() != null) {
            return;
        }
        //    (key  ,value              )
        Map<String, AtomicInteger> frequency1 = getFrequency(words1);
        Map<String, AtomicInteger> frequency2 = getFrequency(words2);

        //   DEBUG          
//        if (LOGGER.isDebugEnabled()) {
//            LOGGER.debug("    1:
{}", getWordsFrequencyString(frequency1)); // LOGGER.debug(" 2:
{}", getWordsFrequencyString(frequency2)); // } // ( ) words1.parallelStream().forEach(word -> word.setWeight(frequency1.get(word.getName()).floatValue())); words2.parallelStream().forEach(word -> word.setWeight(frequency2.get(word.getName()).floatValue())); } /** * * @return */ private static Map<String, AtomicInteger> getFrequency(List<Word> words) { Map<String, AtomicInteger> freq = new HashMap<>(); // words.forEach(i -> freq.computeIfAbsent(i.getName(), k -> new AtomicInteger()).incrementAndGet()); return freq; } /** * : */ private static String getWordsFrequencyString(Map<String, AtomicInteger> frequency) { StringBuilder str = new StringBuilder(); if (frequency != null && !frequency.isEmpty()) { AtomicInteger integer = new AtomicInteger(); frequency.entrySet().stream().sorted((a, b) -> b.getValue().get() - a.getValue().get()).forEach( i -> str.append("\t").append(integer.incrementAndGet()).append("、").append(i.getKey()).append("=") .append(i.getValue()).append("
")); } str.setLength(str.length() - 1); return str.toString(); } /** * */ protected static Map<String, Float> getFastSearchMap(List<Word> words) { if (CollectionUtils.isEmpty(words)) { return Collections.emptyMap(); } Map<String, Float> weightMap = new ConcurrentHashMap<>(words.size()); words.parallelStream().forEach(i -> { if (i.getWeight() != null) { weightMap.put(i.getName(), i.getWeight()); } else { LOGGER.error("no word weight info:" + i.getName()); } }); return weightMap; } }
이 구체 적 인 실현 코드 는 사고 가 매우 긴밀 하기 때문에 어떤 부분 은 비교적 복잡 하 게 쓰 였 으 며,동시에 Atomic Float 원자 류 도 손 으로 썼 다.
6.AtomicFloat 원자 류

import java.util.concurrent.atomic.AtomicInteger;

/**
 * jdk  AtomicFloat,   
 */
public class AtomicFloat extends Number {

    private AtomicInteger bits;

    public AtomicFloat() {
        this(0f);
    }

    public AtomicFloat(float initialValue) {
        bits = new AtomicInteger(Float.floatToIntBits(initialValue));
    }

    //  
    public final float addAndGet(float delta) {
        float expect;
        float update;
        do {
            expect = get();
            update = expect + delta;
        } while (!this.compareAndSet(expect, update));

        return update;
    }

    public final float getAndAdd(float delta) {
        float expect;
        float update;
        do {
            expect = get();
            update = expect + delta;
        } while (!this.compareAndSet(expect, update));

        return expect;
    }

    public final float getAndDecrement() {
        return getAndAdd(-1);
    }

    public final float decrementAndGet() {
        return addAndGet(-1);
    }

    public final float getAndIncrement() {
        return getAndAdd(1);
    }

    public final float incrementAndGet() {
        return addAndGet(1);
    }

    public final float getAndSet(float newValue) {
        float expect;
        do {
            expect = get();
        } while (!this.compareAndSet(expect, newValue));

        return expect;
    }

    public final boolean compareAndSet(float expect, float update) {
        return bits.compareAndSet(Float.floatToIntBits(expect), Float.floatToIntBits(update));
    }

    public final void set(float newValue) {
        bits.set(Float.floatToIntBits(newValue));
    }

    public final float get() {
        return Float.intBitsToFloat(bits.get());
    }

    @Override
    public float floatValue() {
        return get();
    }

    @Override
    public double doubleValue() {
        return (double) floatValue();
    }

    @Override
    public int intValue() {
        return (int) get();
    }

    @Override
    public long longValue() {
        return (long) get();
    }

    @Override
    public String toString() {
        return Float.toString(get());
    }
}
3.총화
대체적인 사고방식 을 다시 한번 훑 어 보다.
(1)선분 사:분 사 는 반드시 일정한 규칙 에 따라 야 한다.그렇지 않 으 면 마음대로 나 누 어도 의미 가 없다.그러면 여 기 는 HanLP 중국어 자연 언어 처리 에서 표준 분 사 를 통 해 분 사 를 한다.
(2)단어의 주파 수 를 통계 한다.위의 단어 가 나타 난 횟수 를 통계 한다.
(3)단어 마다 나타 나 는 횟수 를 통 해 하나의 벡터 로 바 꾸 고 벡터 공식 을 통 해 유사 율 을 계산한다.
이상 은 자바 알고리즘 의 코사인 싱크로 율 계산 문자열 싱크로 율 에 대한 상세 한 내용 입 니 다.자바 알고리즘 에 관 한 자 료 는 다른 관련 글 을 주목 하 시기 바 랍 니 다!

좋은 웹페이지 즐겨찾기