语音转写正确率计算

语音转文字准确率计算 转写正确率的衡量项:ACC、Corr
H = 正确的字数
D = 删减的错误,“我是中国人” “我是中国”
S = 替换的错误,“我是中国人” “我是中华人”
I = 插入的错误,“我是中国人” “我是中国男人”
N = 总字数
ACC = (H - I)/N
Corr= H/N

思路:
sample "我是中国人学大生,今天要测试,录音结束"
test "中国人民生,今天有个大事情,我想吃饭"

语音转写文字,需要遵从文字的语义,所以不能文字出现就算正确,不考虑各种复杂的因素,
要从test中找到sample中对应的字符,并且顺序要按sample中的字符顺序(排除标点符号)

如:
sample中每个字找到的顺序


image.png

那么如何找到正确的文字个数呢?应该就是在这组序号中剔除未找到的-1,然后从剩下的序号中找到最长升序序列(竟然是个算法问题,丢!)


image.png

如图,剔除-1,剩下的就是12,0,1,2,9,4,5,6,最长升序那不就是0,1,2,4,5,6吗,对应的文字就是“中国人生今天”,那么算法如何实现呢?

这里给出个笨办法:
遍历序列,将每个升序数组都保存在list里,如果不是升序,就新建一个list。
如当遇到12,则新建一个list:


image.png

当遇到0,则需要新建一个list


image.png

另外还需要注意,即使是升序,也不一定就能组成最长
如0 1 2,后面是9,如果加进去了,就只能组成0 1 2 9,长度为4,如果放弃加9,则有机会组成0 1 2 4 5 6,长度为6。所以每次添加一个符合升序规则的数字的时候,我们要提前将原list备份一个,留个机会看能否组成更长的序列。

剩下就是计算删减、替换、添加的文字个数了,这个比较简单,看看代码逻辑就行了。
本文代码没有考虑时间复杂度和内存占用(用于测试),请自行优化。
上代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.function.IntPredicate;
import java.util.logging.Logger;

/**
 * 语音转文字准确率计算 转写正确率的衡量项:ACC、Corr H = 正确的字数 D = 删减的错误,“我是中国人”“我是中国” S =
 * 替换的错误,“我是中国人”“我是中华人” I = 插入的错误,“我是中国人”“我是中国男人” N = 总字数 ACC = (H - I)/N
 * Corr= H/N
 */

public class StringCompare {
    private static final String ORIGINAL_STRING = "我是中国人学大生,今天要测试,录音结束";

    private static final String TEST_STRING = "中国人民生,今天有个大事情,我想吃饭";

    private static float mAcc = 0;
    private static float mCorr = 0;

    private static int H = 0;// 正确的字数
    private static int N = 0;// 总字数
    private static int D = 0;// 删减的字数
    private static int S = 0;// 替换的字数
    private static int I = 0;// 插入的字数

    private static List<Character> arrayD = new ArrayList<Character>();
    private static List<Character> arrayI = new ArrayList<Character>();
    private static List<Character> arrayS = new ArrayList<Character>();

    /**
     * 移除标点符号
     */
    private static String removePunctuation(String sentence) {
        String string = sentence.replaceAll("\\pP", "");// 完全清除标点
        System.out.println(string);
        return string;
    }

    private static void print() {
        mAcc = (float) (H - I) / (float) N;
        mCorr = H / (float) N;
        System.out.println("H:" + H + ", N:" + N + ", D:" + D + ", I:" + I + ", S:" + S);
        System.out.println("mAcc" + mAcc + ",mCorr:" + mCorr);
    }

    /*
     * 获取A字符串每个字符在B字符串中的位置
     */
    private static int[] getInIndex(String original, String test) {
        char[] charOriginal = original.toCharArray();
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < charOriginal.length; i++) {
            int tempIndex = test.indexOf(charOriginal[i]);
            System.out.println("tempIndex:" + tempIndex);
            while (list.contains(tempIndex) && tempIndex != -1) {
                System.out.println("while");
                tempIndex = test.indexOf(charOriginal[i], tempIndex + 1);
                System.out.println("tempIndex:" + tempIndex);
            }
            list.add(tempIndex);
            System.out.println("charOriginal[" + i + "]:" + charOriginal[i] + ", index:" + tempIndex);
        }
        return list.stream().mapToInt(Integer::valueOf).toArray();
    }

    // 找出最长的有序list
    private static Map<Integer, Integer> getMaxSortedIndexs(int[] index) {
        List<Map<Integer, Integer>> list = new ArrayList<Map<Integer, Integer>>();
        for (int i = 0; i < index.length; i++) {

            if (index[i] >= 0) {
                System.out.println("cur index:" + index[i]);
                if (list.size() == 0) {
                    list.add(new LinkedHashMap<Integer, Integer>());
                    list.get(list.size() - 1).put(i, index[i]);
                } else {
                    ListIterator<Map<Integer, Integer>> it = list.listIterator();
                    while (it.hasNext()) {
                        Map<Integer, Integer> everyList = it.next();
                        // 与最后一个元素比较
                        if (index[i] > (int) everyList.values().toArray()[everyList.size() - 1]) {
                            Map<Integer, Integer> tempList = new LinkedHashMap<Integer, Integer>();
                            tempList.putAll(everyList);
                            everyList.put(i, index[i]);
                            it.add(tempList);
                        } else {
                            Map<Integer, Integer> tempList = new LinkedHashMap<Integer, Integer>();
                            tempList.put(i, index[i]);
                            it.add(tempList);
                        }
                    }
                }
            }
        }
        System.out.println("list size:" + list.size());
        int longestIndex = 0;
        int maxlength = 0;
        for (int i = 0; i < list.size(); i++) {
            System.out.println("list[" + i + "]:" + list.get(i).toString());
            if (list.get(i).size() > maxlength) {
                maxlength = list.get(i).size();
                longestIndex = i;
            }
        }
        return list.get(longestIndex);
    }

    public static void main(String[] args) {
        long time = System.currentTimeMillis();
        // 拿到每个字符在测试字符串中的位置
        String original = removePunctuation(ORIGINAL_STRING);
        String test = removePunctuation(TEST_STRING);
        int[] index = getInIndex(original, test);
        for (int i = 0; i < index.length; i++) {
            System.out.print(index[i] + "\t");
        }
        System.out.print("\n");
        Map<Integer, Integer> sortedIndex = getMaxSortedIndexs(index);
        System.out.println("cost:" + (System.currentTimeMillis() - time));
        Set<Integer> keySet = sortedIndex.keySet();
        Collection<Integer> valueSet = sortedIndex.values();
        System.out.println("在original字符串中正确的字符");
        System.out.println("[" + ORIGINAL_STRING + "]");
        for (int key : keySet) {
            System.out.println("index:" + key + "value:" + original.charAt(key));
        }
        System.out.println("--------------------------------------------------------------");
        System.out.print("在test字符串中正确的字符\n");
        System.out.println("[" + TEST_STRING + "]");
        for (int key : valueSet) {
            System.out.println("index:" + key + "value:" + test.charAt(key));
        }
        System.out.println("--------------------------------------------------------------");
        System.out.print("计算准确率\n");

        // 每一段的差值都需要计算
        int tempkey = 0;
        int tempValue = 0;
        // 保存每一段的A字符序号的差
        int diffKey = 0;
        // 保存每一段的B字符序号的差
        int diffValue = 0;
        int indexFlag == 0;
        for (Integer key : sortedIndex.keySet()) {
            int value = sortedIndex.get(key);
            if (tempkey == 0 && key != 0 && indexFlag == 0) {
                diffKey = key - tempkey;
            } else if (key == 0) {
                diffKey = 0;
            } else {
                diffKey = key - tempkey - 1;
            }
            if (tempValue == 0 && value != 0 && indexFlag  == 0) {
                diffValue = value - tempValue;
            } else if (value == 0) {
                diffValue = 0;
            } else {
                diffValue = value - tempValue - 1;
            }
            System.err.println("diffKey:" + diffKey + ", diffValue:" + diffValue);
            if (diffKey > diffValue) {
                D += diffKey - diffValue;
                S += diffValue;
            } else if (diffKey == diffValue) {
                S += diffValue;
            } else {
                I += diffValue - diffKey;
                S += diffKey;
            }
            tempkey = key;
            tempValue = value;
            indexFlag ++;
        }
        System.out.println("tempkey:" + tempkey + ",tempValue:" + tempValue);
        diffKey = original.length() - tempkey - 1;
        diffValue = test.length() - tempValue - 1;
        System.out.println("diffKey:" + diffKey + ",diffValue:" + diffValue);
        if (diffKey > diffValue) {
            D += diffKey - diffValue;
            S += diffValue;
        } else if (diffKey == diffValue) {
            S += diffValue;
        } else {
            I += diffValue - diffKey;
            S += diffKey;
        }
        H = sortedIndex.size();
        N = test.length();
        print();
        System.out.println("--------------------------------------------------------------");
    }
}

C#版本

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;

namespace Calibration.utils
{
    class EsrUtils
    {
        private EsrUtils() { }

        /*private static readonly EsrUtils singleInstance = new EsrUtils();

        public static EsrUtils GetInstance
        {
            get
            {
                return singleInstance;
            }
        }*/

        //移除标点符号
        public static string RemovePunctuation(string sentence)
        {
            return Regex.Replace(sentence, "[ \\[ \\] \\^ \\-_*×――(^)$%~!@#$…&%¥—+=<>《》!!???::•`·、。,;,.;\"‘’“”-]", "");
        }


        // 获取A字符串每个字符在B字符串中的位置
        public static int[] GetInIndex(String original, String test)
        {
            char[] charOriginal = original.ToCharArray();
            var list = new List<int>();
            for (int i = 0; i < charOriginal.Length; i++)
            {
                int tempIndex = test.IndexOf(charOriginal[i]);
                Console.WriteLine("tempIndex:" + tempIndex);
                while (list.Contains(tempIndex) && tempIndex != -1)
                {
                    Console.WriteLine("while");
                    tempIndex = test.IndexOf(charOriginal[i], tempIndex + 1);
                    Console.WriteLine("tempIndex:" + tempIndex);
                }
                list.Add(tempIndex);
                Console.WriteLine("charOriginal[" + i + "]:" + charOriginal[i] + ", index:" + tempIndex);
            }
            return list.ToArray();
        }

        // 找出序号数组中最长的升序子序列
        // 目的
        public static Dictionary<int, int> GetMaxSortedIndexs(int[] index)
        {
            List<Dictionary<int, int>> list = new List<Dictionary<int, int>> { };
            for (int i = 0; i < index.Length; i++)
            {

                if (index[i] >= 0)
                {
                    Console.WriteLine("cur index:" + index[i]);
                    if (list.Count == 0)
                    {
                        list.Add(new Dictionary<int, int>());
                        list.Last().Add(i, index[i]);
                    }
                    else
                    {
                        List<Dictionary<int, int>> listBackup = new List<Dictionary<int, int>> { };
                        for (int j = 0; j < list.Count; j++)
                        {
                            Dictionary<int, int> everyList = list[j];
                            // 与最后一个元素比较
                            if (index[i] > everyList.Values.Last())
                            {
                                // 将当前Dictionary备份一个,因为当前的数据添加或者不添加会有两种结果
                                // 如数组 12 0 1 2 9 4 5 6
                                // 如果 0 1 2 后加了9,那只有 0 1 2 9长度为4
                                // 如果 0 1 2 不加9,那就有0 1 2 4 5 6,长度为6
                                Dictionary<int, int> tempList = new Dictionary<int, int>(everyList);
                                listBackup.Add(tempList);
                                everyList.Add(i, index[i]);
                            }
                            else
                            {
                                Dictionary<int, int> tempList = new Dictionary<int, int>();
                                tempList.Add(i, index[i]);
                                listBackup.Add(tempList);
                            }
                        }
                        // list 合并
                        list = list.Union(listBackup).ToList<Dictionary<int, int>>();
                    }
                }
            }
            Console.WriteLine("list size:" + list.Count);
            int longestIndex = 0;
            int maxlength = 0;
            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine("list[" + i + "]:" + list[i]);
                if (list[i].Count > maxlength)
                {
                    maxlength = list[i].Count;
                    longestIndex = i;
                }
            }
            return list[longestIndex];
        }

        public static List<float[]> GetParameters(string originalString, List<string> testString)
        {
            List<float[]> resultList = new List<float[]> { };
            try
            {
                string original = RemovePunctuation(originalString);
                for (int i = 0; i < testString.Count; i++)
                {
                    string test = testString[i];
                    test = RemovePunctuation(test);
                    int[] index = EsrUtils.GetInIndex(original, test);
                    Console.WriteLine("index:" + index);
                    Dictionary<int, int> dic = EsrUtils.GetMaxSortedIndexs(index);
                    int H = 0;
                    int N = 0;
                    int I = 0;
                    int S = 0;
                    int D = 0;
                    float corr = 0;
                    float acc = 0;
                    Dictionary<int, int> sortedIndex = GetMaxSortedIndexs(index);
                    Console.WriteLine("在original字符串中正确的字符");
                    Console.WriteLine("[" + originalString + "]");
                    foreach (int key in dic.Keys)
                    {
                        Console.WriteLine("index:" + key + "value:" + original.ToCharArray()[key]);
                    }
                    Console.WriteLine("--------------------------------------------------------------");
                    Console.WriteLine("在test字符串中正确的字符\n");
                    Console.WriteLine("[" + testString[i] + "]");
                    foreach (int key in dic.Values)
                    {
                        Console.WriteLine("index:" + key + "value:" + test.ToCharArray()[key]);
                    }
                    Console.WriteLine("--------------------------------------------------------------");
                    Console.WriteLine("计算准确率\n");

                    // 每一段的差值都需要计算
                    /*
                    int tempkey = 0;
                    int tempValue = 0;
                    int diffKey = 0;
                    int diffValue = 0;
                    foreach (int key in sortedIndex.Keys)
                    {
                        int value = sortedIndex[key];
                        diffKey = key - tempkey;
                        diffValue = value - tempValue;
                        if (diffKey > diffValue)
                        {
                            D += diffKey - diffValue;
                            S += diffValue;
                        }
                        else if (diffKey == diffValue)
                        {
                            S += diffValue;
                        }
                        else
                        {
                            I += diffValue - diffKey;
                            S += diffKey;
                        }
                        tempkey = key;
                        tempValue = value;
                    }
                    Console.WriteLine("tempkey:" + tempkey + ",tempValue:" + tempValue);
                    diffKey = original.Length - tempkey;
                    diffValue = test.Length - tempValue;
                    if (diffKey > diffValue)
                    {
                        D += diffKey - diffValue;
                        S += diffValue;
                    }
                    else if (diffKey == diffValue)
                    {
                        S += diffValue;
                    }
                    else
                    {
                        I += diffValue - diffKey;
                        S += diffKey;
                    }
                    H = sortedIndex.Count;
                    N = test.Length;
                    */
                    // 每一段的差值都需要计算
                    int tempkey = 0;
                    int tempValue = 0;
                    // 保存每一段的A字符序号的差
                    int diffKey = 0;
                    // 保存每一段的B字符序号的差
                    int diffValue = 0;
                    int indexFlag == 0;
                    foreach (int key in sortedIndex.Keys)
                    {
                        int value = sortedIndex[key];
                        if (tempkey == 0 && key != 0 && indexFlag  == 0) //判断第一位元素
                        {
                            diffKey = key - tempkey;
                        }
                        else if (key == 0)
                        {
                            diffKey = 0;
                        }
                        else
                        {
                            diffKey = key - tempkey - 1;
                        }
                        if (tempValue == 0 && value != 0 && indexFlag  == 0) //判断第一位元素
                        {
                            diffValue = value - tempValue;
                        }
                        else if (value == 0)
                        {
                            diffValue = 0;
                        }
                        else
                        {
                            diffValue = value - tempValue - 1;
                        }
                        Console.WriteLine("diffKey:" + diffKey + ", diffValue:" + diffValue);
                        if (diffKey > diffValue)
                        {
                            D += diffKey - diffValue;
                            S += diffValue;
                        }
                        else if (diffKey == diffValue)
                        {
                            S += diffValue;
                        }
                        else
                        {
                            I += diffValue - diffKey;
                            S += diffKey;
                        }
                        tempkey = key;
                        tempValue = value;
                        indexFlag ++;
                    }
                    Console.WriteLine("tempkey:" + tempkey + ",tempValue:" + tempValue);
                    diffKey = original.Length - tempkey - 1;
                    diffValue = test.Length - tempValue - 1;
                    Console.WriteLine("diffKey:" + diffKey + ",diffValue:" + diffValue);
                    if (diffKey > diffValue)
                    {
                        D += diffKey - diffValue;
                        S += diffValue;
                    }
                    else if (diffKey == diffValue)
                    {
                        S += diffValue;
                    }
                    else
                    {
                        I += diffValue - diffKey;
                        S += diffKey;
                    }
                    H = sortedIndex.Count;
                    N = test.Length;
                    float[] result = new float[7];
                    acc = (float)(H - I) / (float)N;
                    corr = H / (float)N;
                    result[0] = acc;
                    result[1] = corr;
                    result[2] = H;
                    result[3] = N;
                    result[4] = D;
                    result[5] = S;
                    result[6] = I;
                    Console.WriteLine("acc" + acc + ",corr: " + corr);
                    resultList.Add(result);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("error accur:" + e.ToString());
                return null;
            }
            return resultList;
        }

        internal static object GetInstance()
        {
            throw new NotImplementedException();
        }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 用到的组件 1、通过CocoaPods安装 2、第三方类库安装 3、第三方服务 友盟社会化分享组件 友盟用户反馈 ...
    SunnyLeong阅读 14,582评论 1 180
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,652评论 2 59
  • Java工程师成神之路数据一、基础篇1.1 JVM1.1.1. Java内存模型,Java内存管理,Java堆和栈...
    漂泊的灵魂阅读 462评论 0 4
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,018评论 0 4
  • 公元:2019年11月28日19时42分农历:二零一九年 十一月 初三日 戌时干支:己亥乙亥己巳甲戌当月节气:立冬...
    石放阅读 6,864评论 0 2