`

中文分词算法 之 基于词典的正向最大匹配算法

阅读更多

基于词典的正向最大匹配算法(最长词优先匹配),算法会根据词典文件自动调整最大长度,分词的好坏完全取决于词典。

 

算法流程图如下:

 

Java实现代码如下:

 

/**
 * 基于词典的正向最大匹配算法
 * @author 杨尚川
 */
public class WordSeg {
    private static final List<String> DIC = new ArrayList<>();
    private static final int MAX_LENGTH;
    static{
        try {
            System.out.println("开始初始化词典");
            int max=1;
            int count=0;
            List<String> lines = Files.readAllLines(Paths.get("D:/dic.txt"), Charset.forName("utf-8"));
            for(String line : lines){
                DIC.add(line);
                count++;
                if(line.length()>max){
                    max=line.length();
                }
            }
            MAX_LENGTH = max;
            System.out.println("完成初始化词典,词数目:"+count);
            System.out.println("最大分词长度:"+MAX_LENGTH);
        } catch (IOException ex) {
            System.err.println("词典装载失败:"+ex.getMessage());
        }
        
    }
    public static void main(String[] args){
        String text = "杨尚川是APDPlat应用级产品开发平台的作者";  
        System.out.println(seg(text));
    }
    public static List<String> seg(String text){        
        List<String> result = new ArrayList<>();
        while(text.length()>0){
            int len=MAX_LENGTH;
            if(text.length()<len){
                len=text.length();
            }
            //取指定的最大长度的文本去词典里面匹配
            String tryWord = text.substring(0, 0+len);
            while(!DIC.contains(tryWord)){
                //如果长度为一且在词典中未找到匹配,则按长度为一切分
                if(tryWord.length()==1){
                    break;
                }
                //如果匹配不到,则长度减一继续匹配
                tryWord=tryWord.substring(0, tryWord.length()-1);
            }
            result.add(tryWord);
            //从待分词文本中去除已经分词的文本
            text=text.substring(tryWord.length());
        }
        return result;
    }
}

 

词典文件下载地址dic.rar,简单吧,呵呵

 

实现功能是简单,不过这里的词典中词的数目为:427452,我们需要频繁执行DIC.contains(tryWord))来判断一个词是否在词典中,所以优化这行代码能够显著提升分词效率(不要过早优化、不要做不成熟的优化)。

 

上面的代码是利用了JDK的Collection接口的contains方法来判断一个词是否在词典中,而这个方法的不同实现,其性能差异极大,上面的初始版本是用了ArrayList:List<String> DIC = new ArrayList<>()。那么这个ArrayList的性能如何呢?还有更好性能的实现吗?

 

通常来说,对于查找算法,在有序列表中查找比在无序列表中查找更快,分区查找全局遍历要快。

 

通过查看ArrayList、LinkedList、HashSet的contains方法的源代码,发现ArrayList和LinkedList采用全局遍历的方式且未利用有序列表的优势,HashSet使用了分区查找,如果hash分布均匀冲突少,则需要遍历的列表就很少甚至不需要。理论归理论,还是写个代码来测测更直观放心,测试代码如下:

 

/**
 * 比较词典查询算法的性能
 * @author 杨尚川
 */
public class SearchTest {
    //为了生成随机查询的词列表
    private static final List<String> DIC_FOR_TEST = new ArrayList<>();
    //通过更改这里DIC的实现来比较不同实现之间的性能
    private static final List<String> DIC = new ArrayList<>();
    static{
        try {
            System.out.println("开始初始化词典");
            int count=0;
            List<String> lines = Files.readAllLines(Paths.get("D:/dic.txt"), Charset.forName("utf-8"));
            for(String line : lines){
                DIC.add(line);
                DIC_FOR_TEST.add(line);
                count++;
            }
            System.out.println("完成初始化词典,词数目:"+count);
        } catch (IOException ex) {
            System.err.println("词典装载失败:"+ex.getMessage());
        }        
    }
    public static void main(String[] args){
        //选取随机值
        List<String> words = new ArrayList<>();
        for(int i=0;i<100000;i++){
            words.add(DIC_FOR_TEST.get(new Random(System.nanoTime()+i).nextInt(427452)));
        }
        long start = System.currentTimeMillis();
        for(String word : words){
            DIC.contains(word);
        }
        long cost = System.currentTimeMillis()-start;
        System.out.println("cost time:"+cost+" ms");
    }
}

 

#分别运行10次测试,然后取平均值
LinkedList     10000次查询       cost time:48812 ms
ArrayList      10000次查询       cost time:40219 ms
HashSet        10000次查询       cost time:8 ms
HashSet        1000000次查询     cost time:258 ms
HashSet        100000000次查询   cost time:28575 ms

 

我们发现HashSet性能最好,比LinkedList和ArrayList快约3个数量级!这个测试结果跟前面的分析一致,LinkedList要比ArrayList慢一些,虽然他们都是全局遍历,但是LinkedList需要操作下一个数据的引用,所以会多一些操作,LinkedList因为需要保存前驱后继引用,占用的内存也要高一些。

 

虽然HashSet已经有不错的性能了,但是如果词典越来越大,内存占用越来越多怎么办?如果有一个数据结构,有接近HashSet性能的同时,又能对词典的数据进行压缩以减少内存占用,那就完美了。

 

前缀树(Trie)有可能可以实现“鱼与熊掌兼得”的好事,自己实现一个Trie的数据结构,代码如下:

 

/**
 * 前缀树的Java实现
 * 用于查找一个指定的字符串是否在词典中
 * @author 杨尚川
 */
public class Trie {
    private final TrieNode ROOT_NODE = new TrieNode('/');

    public boolean contains(String item){
        //去掉首尾空白字符
        item=item.trim();
        int len = item.length();
        if(len < 1){
            return false;
        }
        //从根节点开始查找
        TrieNode node = ROOT_NODE;
        for(int i=0;i<len;i++){
            char character = item.charAt(i);
            TrieNode child = node.getChild(character);
            if(child == null){
                //未找到匹配节点
                return false;
            }else{
                //找到节点,继续往下找
                node = child;
            }
        }
        if(node.isTerminal()){
            return true;
        }
        return false;
    }
    public void addAll(List<String> items){
        for(String item : items){
            add(item);
        }
    }
    public void add(String item){
        //去掉首尾空白字符
        item=item.trim();
        int len = item.length();
        if(len < 1){
            //长度小于1则忽略
            return;
        }
        //从根节点开始添加
        TrieNode node = ROOT_NODE;
        for(int i=0;i<len;i++){
            char character = item.charAt(i);
            TrieNode child = node.getChildIfNotExistThenCreate(character);
            //改变顶级节点
            node = child;
        }
        //设置终结字符,表示从根节点遍历到此是一个合法的词
        node.setTerminal(true);
    }
    private static class TrieNode{
        private char character;
        private boolean terminal;
        private final Map<Character,TrieNode> children = new ConcurrentHashMap<>();        
        public TrieNode(char character){
            this.character = character;
        }
        public boolean isTerminal() {
            return terminal;
        }
        public void setTerminal(boolean terminal) {
            this.terminal = terminal;
        }        
        public char getCharacter() {
            return character;
        }
        public void setCharacter(char character) {
            this.character = character;
        }
        public Collection<TrieNode> getChildren() {
            return this.children.values();
        }
        public TrieNode getChild(char character) {
            return this.children.get(character);
        }        
        public TrieNode getChildIfNotExistThenCreate(char character) {
            TrieNode child = getChild(character);
            if(child == null){
                child = new TrieNode(character);
                addChild(child);
            }
            return child;
        }
        public void addChild(TrieNode child) {
            this.children.put(child.getCharacter(), child);
        }
        public void removeChild(TrieNode child) {
            this.children.remove(child.getCharacter());
        }        
    }
    
    public void show(){
        show(ROOT_NODE,"");
    }
    private void show(TrieNode node, String indent){
        if(node.isTerminal()){
            System.out.println(indent+node.getCharacter()+"(T)");
        }else{
            System.out.println(indent+node.getCharacter());
        }
        for(TrieNode item : node.getChildren()){
            show(item,indent+"\t");
        }
    }
    public static void main(String[] args){
        Trie trie = new Trie();
        trie.add("APDPlat");
        trie.add("APP");
        trie.add("APD");
        trie.add("Nutch");
        trie.add("Lucene");
        trie.add("Hadoop");
        trie.add("Solr");
        trie.add("杨尚川");
        trie.add("杨尚昆");
        trie.add("杨尚喜");
        trie.add("中华人民共和国");
        trie.add("中华人民打太极");
        trie.add("中华");
        trie.add("中心思想");
        trie.add("杨家将");        
        trie.show();
    }
}

 

 

修改前面的测试代码,把List<String> DIC = new ArrayList<>()改为Trie DIC = new Trie(),使用Trie来做词典查找,最终的测试结果如下:

 

#分别运行10次测试,然后取平均值
LinkedList     10000次查询       cost time:48812 ms
ArrayList      10000次查询       cost time:40219 ms
HashSet        10000次查询       cost time:8 ms
HashSet        1000000次查询     cost time:258 ms
HashSet        100000000次查询   cost time:28575 ms
Trie           10000次查询       cost time:15 ms
Trie           1000000次查询     cost time:1024 ms
Trie           100000000次查询   cost time:104635 ms

 

可以发现Trie和HashSet的性能差异较小,在半个数量级以内,通过jvisualvm惊奇地发现Trie占用的内存比HashSet的大约2.6倍,如下图所示:

 

HashSet:

 

Trie:


 

词典中词的数目为427452,HashSet是基于HashMap实现的,所以我们看到占内存最多的是HashMap$Node、char[]和String,手动执行GC多次,这三种类型的实例数一直在变化,当然都始终大于词数427452。Trie是基于ConcurrentHashMap实现的,所以我们看到占内存最多的是ConcurrentHashMap、ConcurrentHashMap$Node[]、ConcurrentHashMap$Node、Trie$TrieNode和Character,手动执行GC多次,发现Trie$TrieNode的实例数一直保持不变,说明427452个词经过Trie处理后的节点数为603141。

 

很明显地可以看到,这里Trie的实现不够好,选用ConcurrentHashMap占用的内存相当大,那么我们如何来改进呢?把ConcurrentHashMap替换为HashMap可以吗?HashSet不是也基于HashMap吗?看看把ConcurrentHashMap替换为HashMap后的效果,如下图所示:



 

内存占用虽然少了10M左右,但仍然是HashSet的约2.4倍,本来是打算使用Trie来节省内存,没想反正更加占用内存了,既然使用HashMap来实现Trie占用内存极高,那么试试使用数组的方式,如下代码所示:

 

/**
 * 前缀树的Java实现
 * 用于查找一个指定的字符串是否在词典中
 * @author 杨尚川
 */
public class TrieV2 {
    private final TrieNode ROOT_NODE = new TrieNode('/');

    public boolean contains(String item){
        //去掉首尾空白字符
        item=item.trim();
        int len = item.length();
        if(len < 1){
            return false;
        }
        //从根节点开始查找
        TrieNode node = ROOT_NODE;
        for(int i=0;i<len;i++){
            char character = item.charAt(i);
            TrieNode child = node.getChild(character);
            if(child == null){
                //未找到匹配节点
                return false;
            }else{
                //找到节点,继续往下找
                node = child;
            }
        }
        if(node.isTerminal()){
            return true;
        }
        return false;
    }
    public void addAll(List<String> items){
        for(String item : items){
            add(item);
        }
    }
    public void add(String item){
        //去掉首尾空白字符
        item=item.trim();
        int len = item.length();
        if(len < 1){
            //长度小于1则忽略
            return;
        }
        //从根节点开始添加
        TrieNode node = ROOT_NODE;
        for(int i=0;i<len;i++){
            char character = item.charAt(i);
            TrieNode child = node.getChildIfNotExistThenCreate(character);
            //改变顶级节点
            node = child;
        }
        //设置终结字符,表示从根节点遍历到此是一个合法的词
        node.setTerminal(true);
    }
    private static class TrieNode{
        private char character;
        private boolean terminal;
        private TrieNode[] children = new TrieNode[0];
        public TrieNode(char character){
            this.character = character;
        }
        public boolean isTerminal() {
            return terminal;
        }
        public void setTerminal(boolean terminal) {
            this.terminal = terminal;
        }        
        public char getCharacter() {
            return character;
        }
        public void setCharacter(char character) {
            this.character = character;
        }
        public Collection<TrieNode> getChildren() {
            return Arrays.asList(children);            
        }
        public TrieNode getChild(char character) {
            for(TrieNode child : children){
                if(child.getCharacter() == character){
                    return child;
                }
            }
            return null;
        }        
        public TrieNode getChildIfNotExistThenCreate(char character) {
            TrieNode child = getChild(character);
            if(child == null){
                child = new TrieNode(character);
                addChild(child);
            }
            return child;
        }
        public void addChild(TrieNode child) {
            children = Arrays.copyOf(children, children.length+1);
            this.children[children.length-1]=child;
        }
    }
    
    public void show(){
        show(ROOT_NODE,"");
    }
    private void show(TrieNode node, String indent){
        if(node.isTerminal()){
            System.out.println(indent+node.getCharacter()+"(T)");
        }else{
            System.out.println(indent+node.getCharacter());
        }        
        for(TrieNode item : node.getChildren()){
            show(item,indent+"\t");
        }
    }
    public static void main(String[] args){
        TrieV2 trie = new TrieV2();
        trie.add("APDPlat");
        trie.add("APP");
        trie.add("APD");
        trie.add("杨尚川");
        trie.add("杨尚昆");
        trie.add("杨尚喜");
        trie.add("中华人民共和国");
        trie.add("中华人民打太极");
        trie.add("中华");
        trie.add("中心思想");
        trie.add("杨家将");        
        trie.show();
    }
}

 

 

内存占用情况如下图所示:

 

 

现在内存占用只有HashSet方式的80%了,内存问题总算是解决了,进一步分析,如果词典够大,词典中有共同前缀的词足够多,节省的内存空间一定非常客观。那么性能呢?看如下重新测试的数据:

#分别运行10次测试,然后取平均值
LinkedList     10000次查询       cost time:48812 ms
ArrayList      10000次查询       cost time:40219 ms
HashSet        10000次查询       cost time:8 ms
HashSet        1000000次查询     cost time:258 ms
HashSet        100000000次查询   cost time:28575 ms
Trie           10000次查询       cost time:15 ms
Trie           1000000次查询     cost time:1024 ms
Trie           100000000次查询   cost time:104635 
TrieV1         10000次查询       cost time:16 ms
TrieV1         1000000次查询     cost time:780 ms
TrieV1         100000000次查询   cost time:90949 ms
TrieV2         10000次查询       cost time:50 ms
TrieV2         1000000次查询     cost time:4361 ms
TrieV2         100000000次查询   cost time:483398 

 

 

总结一下,ArrayList和LinkedList方式实在太慢,跟最快的HashSet比将近慢约3个数量级,果断抛弃。Trie比HashSet慢约半个数量级,内存占用多约2.6倍,改进的TrieV1比Trie稍微节省一点内存约10%,速度差不多。进一步改进的TrieV2比Trie大大节省内存,只有HashSet的80%,不过速度比HashSet慢约1.5个数量级。

 

TrieV2实现了节省内存的目标,节省了约70%,但是速度也慢了,慢了约10倍,可以对TrieV2做进一步优化,TrieNode的数组children采用有序数组,采用二分查找来加速。

 

下面看看TrieV3的实现:



 

使用了一个新的方法insert来加入数组元素,从无到有构建有序数组,把新的元素插入到已有的有序数组中,insert的代码如下:

 

        /**
         * 将一个字符追加到有序数组
         * @param array 有序数组
         * @param element 字符
         * @return 新的有序数字
         */
        private TrieNode[] insert(TrieNode[] array, TrieNode element){
            int length = array.length;
            if(length == 0){
                array = new TrieNode[1];
                array[0] = element;
                return array;
            }
            TrieNode[] newArray = new TrieNode[length+1];
            boolean insert=false;
            for(int i=0; i<length; i++){
                if(element.getCharacter() <= array[i].getCharacter()){
                    //新元素找到合适的插入位置
                    newArray[i]=element;
                    //将array中剩下的元素依次加入newArray即可退出比较操作
                    System.arraycopy(array, i, newArray, i+1, length-i);
                    insert=true;
                    break;
                }else{
                    newArray[i]=array[i];
                }
            }
            if(!insert){
                //将新元素追加到尾部
                newArray[length]=element;
            }
            return newArray;
        }

 

 

有了有序数组,在搜索的时候就可以利用有序数组的优势,重构搜索方法getChild:



  

数组中的元素是TrieNode,所以需要自定义TrieNode的比较方法:



 

好了,一个基于有序数组的二分搜索的性能提升重构就完成了,良好的单元测试是重构的安全防护网,没有单元测试的重构就犹如高空走钢索却没有防护垫一样危险,同时,不过早优化不做不成熟的优化是我们应该谨记的原则,要根据应用的具体场景在算法的时空中做权衡。

 

OK,看看TrieV3的性能表现,当然了,内存使用没有变化,和TrieV2一样:

 

TrieV2         10000次查询       cost time:50 ms
TrieV2         1000000次查询     cost time:4361 ms
TrieV2         100000000次查询   cost time:483398 ms
TrieV3         10000次查询       cost time:21 ms
TrieV3         1000000次查询     cost time:1264 ms
TrieV3         100000000次查询   cost time:121740 ms

 

 

提升效果很明显,约4倍。性能还有提升的空间吗?呵呵......

 

代码托管于GITHUB

 

参考资料:

1、中文分词十年回顾

2、中文信息处理中的分词问题

3、汉语自动分词词典机制的实验研究

4、由字构词_中文分词新方法

5、汉语自动分词研究评述

 

NUTCH/HADOOP视频教程

 

  • 大小: 12 KB
  • 大小: 34.1 KB
  • 大小: 39.2 KB
  • 大小: 39.2 KB
  • 大小: 39.5 KB
  • 大小: 11.8 KB
  • 大小: 32.4 KB
  • 大小: 23.5 KB
8
5
分享到:
评论
12 楼 yangshangchuan 2015-04-15  
math1141 写道
yangshangchuan 写道
math1141 写道
yangshangchuan 写道
math1141 写道
拜读大作啦!发现词库很重要呀。所以不知道博主能分享一些如何生成词库的方法么?自己爬维基百科?


网上找一些免费的人工标注的语料库: https://github.com/ysc/word/tree/master/src/main/resources/corpus


多谢您及时的回答,我网上看了下有标注的语料库,有98年人民日报和MSR的,请问您还知道哪些么?打算做个全集来提高分词的精度。
还有从网上描述看,这些都是一些规范加软件工具加人工审核来做的,所以很费时间。如果自己想做一个比如数学专业的词库,也得这样来弄么?多谢了。


只能这么弄了。


好滴,多谢了。


Not at all.
11 楼 math1141 2015-04-15  
yangshangchuan 写道
math1141 写道
yangshangchuan 写道
math1141 写道
拜读大作啦!发现词库很重要呀。所以不知道博主能分享一些如何生成词库的方法么?自己爬维基百科?


网上找一些免费的人工标注的语料库: https://github.com/ysc/word/tree/master/src/main/resources/corpus


多谢您及时的回答,我网上看了下有标注的语料库,有98年人民日报和MSR的,请问您还知道哪些么?打算做个全集来提高分词的精度。
还有从网上描述看,这些都是一些规范加软件工具加人工审核来做的,所以很费时间。如果自己想做一个比如数学专业的词库,也得这样来弄么?多谢了。


只能这么弄了。


好滴,多谢了。
10 楼 yangshangchuan 2015-04-15  
math1141 写道
yangshangchuan 写道
math1141 写道
拜读大作啦!发现词库很重要呀。所以不知道博主能分享一些如何生成词库的方法么?自己爬维基百科?


网上找一些免费的人工标注的语料库: https://github.com/ysc/word/tree/master/src/main/resources/corpus


多谢您及时的回答,我网上看了下有标注的语料库,有98年人民日报和MSR的,请问您还知道哪些么?打算做个全集来提高分词的精度。
还有从网上描述看,这些都是一些规范加软件工具加人工审核来做的,所以很费时间。如果自己想做一个比如数学专业的词库,也得这样来弄么?多谢了。


只能这么弄了。
9 楼 math1141 2015-04-15  
yangshangchuan 写道
math1141 写道
拜读大作啦!发现词库很重要呀。所以不知道博主能分享一些如何生成词库的方法么?自己爬维基百科?


网上找一些免费的人工标注的语料库: https://github.com/ysc/word/tree/master/src/main/resources/corpus


多谢您及时的回答,我网上看了下有标注的语料库,有98年人民日报和MSR的,请问您还知道哪些么?打算做个全集来提高分词的精度。
还有从网上描述看,这些都是一些规范加软件工具加人工审核来做的,所以很费时间。如果自己想做一个比如数学专业的词库,也得这样来弄么?多谢了。
8 楼 yangshangchuan 2015-04-15  
math1141 写道
拜读大作啦!发现词库很重要呀。所以不知道博主能分享一些如何生成词库的方法么?自己爬维基百科?


网上找一些免费的人工标注的语料库: https://github.com/ysc/word/tree/master/src/main/resources/corpus
7 楼 math1141 2015-04-15  
拜读大作啦!发现词库很重要呀。所以不知道博主能分享一些如何生成词库的方法么?自己爬维基百科?
6 楼 jasstion 2014-04-29  
对着个有过研究,我觉得用有向图来实现即节省空间又节省查询的时间,
5 楼 yangshangchuan 2014-04-29  
a8522816 写道
杨大大,图片上那个性能监控程序是啥。

jvisualvm
4 楼 a8522816 2014-04-28  
杨大大,图片上那个性能监控程序是啥。
3 楼 yangshangchuan 2014-03-17  
申公子 写道
词典一大 效率不就很低了


还可以使用Bloom filter,如果能容忍一定的误差:如果Bloom filter判断词典中没有 杨尚川 这个词,那么肯定是没有的;如果Bloom filter判断词典中 杨尚川 这个词,那么词典中可能没有
2 楼 yangshangchuan 2014-03-17  
申公子 写道
词典一大 效率不就很低了

我这里只是个简单的演示,实际中可以把词典转换为Trie树结构,这样在查词典的时候效率就好很多。
1 楼 申公子 2014-03-17  
词典一大 效率不就很低了

相关推荐

    AMESim仿真平台在电动汽车热泵空调系统设计与优化的应用解析

    内容概要:本文深入探讨了AMESim仿真平台在电动汽车(EV)热泵空调系统设计与优化中的应用。首先介绍了AMESim的基础建模方法,如构建制冷循环模型中的压缩机、蒸发器和冷凝器等组件,并详细解释了各部件的工作原理及其参数设定。接着重点阐述了EV热泵空调系统的特殊之处,即不仅能够制冷还可以在冬季提供高效的制热功能,这对于提高电动汽车在寒冷条件下的续航里程和乘坐舒适性非常重要。文中给出了几个具体的案例,包括通过改变压缩机运行频率来进行性能优化,以及针对低温环境下热泵系统的控制策略,如四通阀切换逻辑、电子膨胀阀开度调节等。此外,还讨论了热泵系统与其他子系统(如电池温控)之间的协同工作方式,强调了系统集成的重要性。最后分享了一些实用的经验技巧,例如如何避免仿真过程中可能出现的问题,怎样评估系统的整体性能等。 适合人群:从事汽车工程、暖通空调(HVAC)领域的研究人员和技术人员,特别是关注新能源汽车热管理系统的专业人士。 使用场景及目标:适用于希望深入了解电动汽车热泵空调系统特性的工程师们,旨在帮助他们掌握基于AMESim进行系统建模、仿真分析的方法论,以便更好地指导实际产品研发。 阅读建议:由于涉及到较多的专业术语和技术细节,建议读者具备一定的机械工程背景知识,同时配合官方文档或其他参考资料一起研读,以加深理解。

    dtcwt 双树复小波的matlab工具箱

    dtcwt 双树复小波的matlab工具箱。内容来源于网络分享,如有侵权请联系我删除。

    基于Hadoop的朴素贝叶斯分类(MapReduce实现).zip

    基于hadoop的系统

    永磁同步电机中电流预测控制与广义预测控制(速度环)的技术解析及应用

    内容概要:本文探讨了永磁同步电机(PMSM)控制系统中两种先进的控制策略:电流预测控制和广义预测控制(GPC),特别是在速度环中结合扩展状态观测器(ESO)的应用。文章首先介绍了广义预测控制的基本原理及其在速度环中的实现方式,强调了其通过滚动优化对未来系统输出进行预测的能力。接着讨论了电流环中采用的双矢量改进预测控制算法,该算法通过优化两个电压矢量的选择提高了电流控制的精度和动态响应速度。此外,文章还提供了具体的代码示例和技术细节,帮助读者更好地理解和实现这些控制策略。最后,推荐了几篇相关文献供进一步学习。 适合人群:从事电机控制领域的研究人员、工程师以及对预测控制感兴趣的高校师生。 使用场景及目标:适用于需要提高永磁同步电机控制系统性能的研究项目或工业应用场景,旨在实现更精确、高效的电机控制,增强系统的鲁棒性和稳定性。 其他说明:文中提到的方法已在实验室环境中进行了验证,并取得了显著的效果,如减小了突加负载时的速度跌落幅度,降低了电流谐波失真度等。同时,作者分享了一些实用的调试技巧和注意事项,有助于加速实际项目的开发进程。

    期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)

    期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目),个人经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做大作业的学生和需要项目实战练习的学习者,可作为毕业设计、课程设计、期末大作业,代码资料完整,下载可用。 期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作业Python实现基于图神经网络的信任评估项目源代码+使用说明(高分项目)期末作

    开源6轴机械臂控制器SmallRobotArm AR3:离线控制与运动学算法详解

    内容概要:本文详细介绍了开源6轴机械臂控制器SmallRobotArm AR3的功能特点和技术细节。首先,文章展示了AR3可以直接通过板载按钮进行关节和坐标运动控制,无需连接电脑,提供了便捷的操作体验。其次,深入探讨了其核心算法,包括正逆解算法、运动模式切换逻辑以及平滑处理机制。此外,还介绍了自动标定程序、G代码支持和扩展功能如手势控制等特性。最后,强调了AR3的高扩展性和易用性,使其成为机器人爱好者和专业开发者的理想选择。 适合人群:对机器人技术和机械臂感兴趣的初学者、中级开发者及研究人员。 使用场景及目标:适用于教育、科研、DIY项目等领域,旨在帮助用户快速掌握机械臂控制原理并应用于实际任务中。 其他说明:文中提供的代码片段有助于理解和实现相关功能,而详细的硬件介绍则为动手能力强的用户提供改装灵感。

    编程竞赛蓝桥杯Python模拟题集锦与解析:涵盖字符串处理、数字运算及算法设计

    内容概要:本文档提供了10道蓝桥杯Python模拟题及其详细解答过程,涵盖字符串处理、数字运算、算法设计等多个方面。题目包括数字反转、字母转换、数字分段和、质数判断、字符串统计、数独验证、最大子数组和、括号匹配、斐波那契数列和文件统计。每道题目不仅给出了详细的解题思路和分析,还附有完整的Python源代码。通过这些题目,读者可以系统地提升编程能力和算法思维,掌握常见的编程技巧和方法。 适合人群:适合有一定编程基础的Python学习者,特别是准备参加蓝桥杯或其他编程竞赛的学生和爱好者。 使用场景及目标:①作为蓝桥杯赛前训练资料,帮助参赛者熟悉比赛题型和解题思路;②作为编程练习题集,巩固Python语言的基础知识和常用算法;③通过实际编程练习,提高解决实际问题的能力和编程水平。 阅读建议:建议读者先尝试独立完成每道题目,然后再参考提供的解题思路和代码,对比自己的解法,找出差距并加以改进。同时,注意理解每道题目背后的算法思想和编程技巧,以便举一反三,灵活应用。

    web_6_login.rar

    web_6_login.rar

    AI插件实用脚本illustrator-scripts-master

    脚本插件 1.Ai转PS矢量图层 2.分割线段 3.图形变换 4.圆形填充 5.文字块排版 6.多页PDF文档置入 将jsx文件复制到\Abobe Illustrator XX\Presets(在部分AI软件中可能显示为“预设”)\zh_CN\脚本 文件夹下,重新启动ai,就可以在"文件"-"脚本"下看见ai脚本菜单,运行即可。

    嵌入式系统中滑模观测器与PLL的C代码实现及其在STM32F1平台的应用

    内容概要:本文详细介绍了滑模观测器和PLL在STM32F1平台上的C代码实现。滑模观测器用于估计系统内部状态,尤其适用于电机控制领域;PLL则用于确保输出信号相位与输入信号相位保持一致。文中展示了两种滑模观测器的实现方法:一种采用符号函数进行硬切换,另一种采用饱和函数进行软化处理。此外,文章还强调了使用TI的IQmath库进行定点计算加速,以提高运算效率并减少资源占用。通过具体的代码示例和调试技巧,作者分享了如何在STM32F1平台上实现高效稳定的滑模观测器和PLL系统。 适合人群:嵌入式系统开发者、电机控制系统工程师、熟悉C语言编程的技术人员。 使用场景及目标:① 实现高效的滑模观测器和PLL系统,应用于电机控制和其他实时性要求较高的场景;② 学习如何使用IQmath库进行定点计算加速,优化嵌入式系统的性能;③ 掌握调试技巧,确保系统稳定运行。 其他说明:文章提供了详细的代码示例和调试经验,帮助读者更好地理解和实现滑模观测器和PLL系统。同时,文中提到的一些注意事项和常见问题解决方案也非常实用。

    基于纳什谈判与ADMM的共享储能电站优化运行解决方案

    内容概要:本文探讨了利用纳什谈判理论和交替方向乘子法(ADMM)解决共享储能电站中多用户之间的利益分配问题。文中详细介绍了将复杂的利益分配问题转化为数学模型的方法,以及如何通过ADMM算法实现分布式优化,确保各参与方都能接受的最优解。同时,文章还展示了实际应用案例,证明了该方法的有效性和优越性。 适合人群:从事电力系统优化、储能技术研究的专业人士,以及对分布式优化算法感兴趣的科研人员。 使用场景及目标:适用于多个用户共同使用储能设施的场景,旨在通过科学合理的算法设计,实现储能系统的高效运行和利益的最大化分配。 其他说明:文章不仅提供了详细的算法实现步骤,还包括了一些实用的代码片段和实验结果分析,帮助读者更好地理解和应用相关技术。此外,文中提到的一些反直觉现象也为进一步的研究提供了思路。

    08011车TC1车ER(A、B网)通讯故障分析报告 .docx

    08011车TC1车ER(A、B网)通讯故障分析报告 .docx

    2025年机器人+人工智能工业应用研究报告.pdf

    2025年机器人+人工智能工业应用研究报告.pdf

    智能优化领域的麻雀搜索算法(DEH_SSA)改进及其Python实现

    内容概要:本文深入探讨了麻雀搜索算法(SSA)的一种改进版本——融合差分进化和多策略的麻雀搜索算法(DEH_SSA)。文章首先介绍了反向学习初始化种群、非线性因子改进发现者策略、改进警觉性策略、融合差分算法以及精英扰动策略五大创新点。接着详细展示了这些策略的具体实现方法,如反向学习初始化通过计算反向解使初始种群分布更合理,非线性因子改进发现者策略通过动态调整搜索步长提高搜索效率等。此外,文中提供了23个基准测试函数的实验结果,证明了DEH_SSA相比传统SSA在收敛速度和最优解质量上的显著优势。最后给出了详细的调参指南,帮助初学者更好地理解和应用该算法。 适合人群:对智能优化算法感兴趣的研究人员和技术开发者,尤其是有一定编程基础并对群体智能算法有初步了解的人士。 使用场景及目标:适用于需要解决复杂优化问题的场景,如工程优化、机器学习超参数调优等领域。目标是提供一种高效的优化工具,帮助用户更快更精确地找到全局最优解。 其他说明:文章不仅提供了理论解释,还有丰富的代码实例,便于读者动手实践。同时,附带的调参指南有助于读者根据具体问题调整算法参数,获得更好的优化效果。

    西门子WinCC报表系统多版本通用模板及优化技术详解

    内容概要:本文详细介绍了西门子WinCC报表系统的多版本通用模板及其优化技术。涵盖了日报表、月报表、年报表、自由报表及班次报表等多种类型的报表模板,提供了详细的代码示例,包括VBS脚本、SQL查询语句、C脚本等。文中强调了性能优化措施,如索引建立、参数化查询、存储过程的应用等,并附有配套的视频教程帮助理解和实践。此外,还讨论了班次报表的灵活性设计、数据分页技术、错误处理机制等方面的内容。 适合人群:已经具备WinCC脚本基础和SQL语言基础的技术人员,尤其是从事工业自动化领域的工程师。 使用场景及目标:适用于需要频繁生成各类生产报表的企业,旨在提高数据查询效率,满足不同客户的定制化需求,同时确保系统的稳定性和兼容性。通过学习本文提供的模板和技术,用户能够更好地应对复杂的生产数据管理和报表生成任务。 其他说明:文中提到的所有技术手段均经过实际测试验证,可在多个版本的WinCC环境中稳定运行。配套的视频教程进一步降低了学习门槛,使用户能够更快地上手操作。

    ANPC并网逆变器的SPWM控制与电流闭环仿真实现

    内容概要:本文详细介绍了ANPC并网逆变器的闭环仿真建模过程,涵盖了直流电压源的稳定接入、SPWM调制、电流闭环控制以及锁相环的应用。作者通过具体的代码示例和技术细节,展示了如何利用SPWM生成稳定的正弦波,通过锁相环确保电流和电压的相位一致,并采用前馈解耦提高电流控制的精度。同时,文中还讨论了一些常见的仿真问题及其解决方案,如死区效应、调制比限制和电流环PI参数的优化。 适合人群:电力电子工程师、控制系统设计师、从事逆变器研究的技术人员。 使用场景及目标:适用于希望深入了解ANPC并网逆变器控制策略的研究人员和工程师,旨在帮助他们掌握SPWM调制、电流闭环控制和锁相环的设计与实现。 其他说明:文章提供了丰富的代码片段和实践经验,有助于读者快速理解和应用相关技术。此外,文中提到的一些常见问题和解决方案也为实际项目提供了宝贵的参考。

    groovy-3.0.7.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    groovy-2.4.9.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    thumbnailator-0.4.16.jar中文-英文对照文档.zip

    # 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    基于折射反向学习和自适应惯性权重的MATLAB蝴蝶优化算法改进及其应用

    内容概要:本文深入探讨了基于折射反向学习策略和自适应惯性权重机制改进的蝴蝶优化算法(BOA)。首先介绍了折射对立学习策略用于构建精英种群的方法,通过折射对立操作提高种群质量和多样性。接着阐述了自适应惯性权重机制的作用,即通过动态调整权重来平衡全局搜索和局部开发的能力。文中详细展示了这两种改进策略的具体MATLAB代码实现,并通过23种测试函数进行了性能对比,证明改进后的BOA在复杂多峰函数上表现出显著优势。此外,文章还讨论了改进算法在工程优化问题中的应用实例,如光伏阵列参数优化,展示了其实用价值。 适合人群:对优化算法感兴趣的科研人员、研究生以及从事相关领域的工程师。 使用场景及目标:适用于解决复杂的多峰优化问题,特别是在需要高效求解全局最优解的情况下。目标是提供一种改进的BOA算法,能够更好地应对复杂优化任务,提高求解效率和准确性。 其他说明:文章提供了详细的代码注释和测试数据,便于读者理解和复现实验结果。同时,文中还分享了一些实用的小技巧,如如何调整参数以应对不同类型的优化问题。

Global site tag (gtag.js) - Google Analytics