大数据(7z)Scala手写中文分词

Spark 大数据中文分词统计(三) Scala语言实现分词统计 Java版的Spark大数据中文分词统计程序完成之后,又经过一周的努力,把Scala版的Spark 大数据中文分词统计程序也搞出来了,在此分享给各位想学习Spark的朋友。         如下是程序最终运行的界面截图,和Java版差别不大:                 如下是Scala工程结构:           当你在工程主类文件WordCounter.scala上单击右 阅读详情

1、手写中文分词极简代码

  • 徒手编写Scala中文分词【贝叶斯网络+动态规划】
  • 点击此处可查看中文分词算法原理
  • 用法:传入自定义词典(格式Map[String, Int])创建对象,然后cut即可
import scala.collection.mutable
import scala.math.log10

class Tokenizer(var w2f: Map[String, Int]) {
  var total: Int = w2f.values.sum
  var maxLen: Int = w2f.keys.map(_.length).max
  val reEng = "[a-zA-Z]+"
  val reNum = "[0-9]+%?|[0-9]+[.][0-9]+%?"

  def cut(clause: String): mutable.ListBuffer[String] = {
    // 句子长度
    val len = clause.length
    // 有向无环图
    val DAG: mutable.Map[Int, mutable.ListBuffer[Int]] = mutable.Map()
    // 词图扫描
    for (head <- 0 until len) {
      val tail = len.min(head + maxLen)
      DAG.update(head, mutable.ListBuffer(head))
      for (mid <- (head + 2) until (tail + 1)) {
        val word = clause slice(head, mid)
        // 词库匹配
        if (w2f.contains(word)) DAG(head).append(mid - 1)
        // 英文匹配
        else if (word.matches(reEng)) DAG(head).append(mid - 1)
        // 数字匹配
        else if (word.matches(reNum)) DAG(head).append(mid - 1)
      }
    }
    // 最短路径
    val route: mutable.Map[Int, (Double, Int)] = mutable.Map(len -> (0.0, 0))
    // 概率对数总值
    val logTotal: Double = log10(total)
    // 动态规划
    for (idx <- Range(len - 1, -1, -1)) {
      var maxStatus: (Double, Int) = (-9e99, 0)
      for (x <- DAG(idx)) {
        val freq: Int = w2f.getOrElse(clause.slice(idx, x + 1), 1)
        val logFreq: Double = log10(freq)
        val lastStatus: Double = route(x + 1)._1
        val status: Double = logFreq - logTotal + lastStatus
        if (status > maxStatus._1) {
          maxStatus = (status, x)
        }
      }
      route.update(idx, maxStatus)
    }
    // 分词列表
    val words: mutable.ListBuffer[String] = mutable.ListBuffer()
    // 根据最短路径取词
    var x: Int = 0
    while (x < len) {
      val y: Int = route(x)._2 + 1
      val l_word: String = clause.slice(x, y)
      words.append(l_word)
      x = y
    }
    return words
  }
}

object Hello {
  def main(args: Array[String]): Unit = {
    val w2f = Map("空调" -> 2, "调和" -> 2, "和风" -> 2, "风扇" -> 2, "和" -> 2)
    val tk: Tokenizer = new Tokenizer(w2f)
    println(tk.cut("空调和风扇abc123"))
  }
}
分词结果
ListBuffer(空调, 和, 风扇, a, bc, 1, 23)

object Hello {
  def main(args: Array[String]): Unit = {
    val w2f = Map("空调" -> 2, "调和" -> 2, "和风" -> 2, "风扇" -> 2, "和" -> 2)
    val tk: Tokenizer = new Tokenizer(w2f)
    val a1 = List("空调和风扇", "空调和风99km", "99km", "空调风扇")
    val a2 = a1.flatMap(tk.cut)
    val a3 = a2.groupBy(e => e)
    val a4 = a3.map(kv => (kv._1, kv._2.length))
    println(a4.toList.sortBy(x => x._2).reverse)
  }
}
中文词频统计
List((空调,3), (风扇,2), (km,2), (99,2), (和风,1), (和,1))

2、中文分词+Spark词频统计

注意:分词器要继承序列化

class Tokenizer(var w2f: Map[String, Int]) extends Serializable {

  import scala.collection.mutable
  import scala.math.log10

  var total: Int = w2f.values.sum
  var maxLen: Int = w2f.keys.map(_.length).max
  val reEng = "[a-zA-Z]+"
  val reNum = "[0-9]+%?|[0-9]+[.][0-9]+%?"

  def cut(clause: String): mutable.ListBuffer[String] = {
    // 句子长度
    val len = clause.length
    // 有向无环图
    val DAG: mutable.Map[Int, mutable.ListBuffer[Int]] = mutable.Map()
    // 词图扫描
    for (head <- 0 until len) {
      val tail = len.min(head + maxLen)
      DAG.update(head, mutable.ListBuffer(head))
      for (mid <- (head + 2) until (tail + 1)) {
        val word = clause slice(head, mid)
        // 词库匹配
        if (w2f.contains(word)) DAG(head).append(mid - 1)
        // 英文匹配
        else if (word.matches(reEng)) DAG(head).append(mid - 1)
        // 数字匹配
        else if (word.matches(reNum)) DAG(head).append(mid - 1)
      }
    }
    // 最短路径
    val route: mutable.Map[Int, (Double, Int)] = mutable.Map(len -> (0.0, 0))
    // 概率对数总值
    val logTotal: Double = log10(total)
    // 动态规划
    for (idx <- Range(len - 1, -1, -1)) {
      var maxStatus: (Double, Int) = (-9e99, 0)
      for (x <- DAG(idx)) {
        val freq: Int = w2f.getOrElse(clause.slice(idx, x + 1), 1)
        val logFreq: Double = log10(freq)
        val lastStatus: Double = route(x + 1)._1
        val status: Double = logFreq - logTotal + lastStatus
        if (status > maxStatus._1) {
          maxStatus = (status, x)
        }
      }
      route.update(idx, maxStatus)
    }
    // 分词列表
    val words: mutable.ListBuffer[String] = mutable.ListBuffer()
    // 根据最短路径取词
    var x: Int = 0
    while (x < len) {
      val y: Int = route(x)._2 + 1
      val l_word: String = clause.slice(x, y)
      words.append(l_word)
      x = y
    }
    return words
  }
}

object Hello {
  def main(args: Array[String]): Unit = {
    // 创建SparkContext对象,传入SparkConf配置
    import org.apache.spark.{SparkContext, SparkConf}
    val conf = new SparkConf().setAppName("a").setMaster("local[2]")
    val sc = new SparkContext(conf)
    // 创建中文分词器
    val w2f = Map("空调" -> 2, "调和" -> 2, "和风" -> 2, "风扇" -> 2, "和" -> 2)
    val tk: Tokenizer = new Tokenizer(w2f)
    // 制作第一个RDD
    val r = sc.makeRDD(Seq("空调和风扇", "空调和风99km", "99km", "空调风扇"))
    // 中文分词、词频统计、降序
    print(r.flatMap(tk.cut).map((_, 1)).reduceByKey(_ + _).collect.sortBy(~_._2).toList)
    // 关闭连接
    sc.stop()
  }
}

结果打印

List((空调,3), (km,2), (99,2), (风扇,2), (和风,1), (和,1))

3、中文分词+Spark文本分类

继承org.apache.spark.ml.feature.Tokenizer,重写createTransformFunc

import org.apache.spark.ml.feature.Tokenizer

class Jieba(var w2f: Map[String, Int]) extends Tokenizer {

  import scala.collection.mutable
  import scala.math.log10

  var total: Int = w2f.values.sum
  var maxLen: Int = w2f.keys.map(_.length).max
  val reEng = "[a-zA-Z]+"
  val reNum = "[0-9]+%?|[0-9]+[.][0-9]+%?"

  def cut(clause: String): Seq[String] = {
    // 句子长度
    val len = clause.length
    // 有向无环图
    val DAG: mutable.Map[Int, mutable.ListBuffer[Int]] = mutable.Map()
    // 词图扫描
    for (head <- 0 until len) {
      val tail = len.min(head + maxLen)
      DAG.update(head, mutable.ListBuffer(head))
      for (mid <- (head + 2) until (tail + 1)) {
        val word = clause slice(head, mid)
        // 词库匹配
        if (w2f.contains(word)) DAG(head).append(mid - 1)
        // 英文匹配
        else if (word.matches(reEng)) DAG(head).append(mid - 1)
        // 数字匹配
        else if (word.matches(reNum)) DAG(head).append(mid - 1)
      }
    }
    // 最短路径
    val route: mutable.Map[Int, (Double, Int)] = mutable.Map(len -> (0.0, 0))
    // 概率对数总值
    val logTotal: Double = log10(total)
    // 动态规划
    for (idx <- Range(len - 1, -1, -1)) {
      var maxStatus: (Double, Int) = (-9e99, 0)
      for (x <- DAG(idx)) {
        val freq: Int = w2f.getOrElse(clause.slice(idx, x + 1), 1)
        val logFreq: Double = log10(freq)
        val lastStatus: Double = route(x + 1)._1
        val status: Double = logFreq - logTotal + lastStatus
        if (status > maxStatus._1) {
          maxStatus = (status, x)
        }
      }
      route.update(idx, maxStatus)
    }
    // 分词列表
    val words: mutable.ListBuffer[String] = mutable.ListBuffer()
    // 根据最短路径取词
    var x: Int = 0
    while (x < len) {
      val y: Int = route(x)._2 + 1
      val l_word: String = clause.slice(x, y)
      words.append(l_word)
      x = y
    }
    words
  }

  override protected def createTransformFunc: String => Seq[String] = {
    cut
  }
}

object Hello {
  def main(args: Array[String]): Unit = {
    //创建SparkSession对象
    import org.apache.spark.sql.SparkSession
    val spark: SparkSession = SparkSession.builder()
      .master("local[*]").appName("a1").getOrCreate()
    //隐式转换支持
    import spark.implicits._
    // 中分分词器
    val jieba = new Jieba(
      """
        |优秀 好味 精彩 软滑 白嫩 干货 超神 醍醐灌顶 不要不要的 普通 一般般 无感 中规中矩
        |乏味 中立 还行 可以可以 难吃 金玉其外 发货慢 无语 弱鸡 呵呵 水货 渣渣 超鬼
        |""".stripMargin.split("\\s").filter(_.nonEmpty).map((_, 2)).toMap
    )
    // 创建数据
    val label = Seq(("好评", 0), ("中评", 1), ("差评", 2))
    val sentenceDf = Seq(
      ("好评", "优秀好味精彩软滑白嫩干货超神醍醐灌顶不要不要的"),
      ("中评", "普通一般般无感中规中矩乏味中立还行可以可以"),
      ("差评", "难吃金玉其外发货慢无语弱鸡呵呵水货渣渣超鬼"),
    ).toDF("comment", "sentence")
    val yx = sentenceDf.join(label.toDF("comment", "label"), "comment")
    // 特征工程
    import org.apache.spark.ml.feature.{HashingTF, IDF}
    // 分词
    val tokenizer = jieba.setInputCol("sentence").setOutputCol("words")
    val wordsDf = tokenizer.transform(yx)
    // 编码
    val hashingTF = new HashingTF()
      .setInputCol("words").setOutputCol("rawFeatures").setNumFeatures(10)
    val hashingDf = hashingTF.transform(wordsDf)
    // TF-IDF训练+转换
    val idf = new IDF().setInputCol("rawFeatures").setOutputCol("features")
    val idfModel = idf.fit(hashingDf)
    val tfidfDf = idfModel.transform(hashingDf)
    tfidfDf.show(numRows = 9, truncate = false)
    // 逻辑回归
    import org.apache.spark.ml.classification.LogisticRegression
    val lr = new LogisticRegression()
      .setFeaturesCol("features")
      .setLabelCol("label")
      .setPredictionCol("prediction")
      .setProbabilityCol("Probability")
    // 逻辑回归拟合
    val fittedLr = lr.fit(tfidfDf)
    // 预测
    val prediction = fittedLr.transform(
      idfModel.transform(
        hashingTF.transform(
          tokenizer.transform(
            Seq("无感乏味", "呵呵渣渣", "干货好味").toDF("sentence")
          )
        )
      )
    )
    prediction
      .join(label.toDF("predictedComment", "prediction"), "prediction")
      .select("sentence", "words", "predictedComment").show()
  }
}

结果打印

4、HMM分词(不带词典)

import scala.collection.mutable

class HmmTokenizer {
  val minDouble: Double = Double.MinValue
  val PrevStatus: Map[Char, String] = Map(
    'B' -> "ES",
    'M' -> "MB",
    'S' -> "SE",
    'E' -> "BM")
  val startP: Map[Char, Double] = Map(
    'B' -> -0.26268660809250016,
    'E' -> minDouble,
    'M' -> minDouble,
    'S' -> -1.4652633398537678)
  val transP: Map[Char, Map[Char, Double]] = Map(
    'B' -> Map('E' -> -0.51082562376599, 'M' -> -0.916290731874155),
    'E' -> Map('B' -> -0.5897149736854513, 'S' -> -0.8085250474669937),
    'M' -> Map('E' -> -0.33344856811948514, 'M' -> -1.2603623820268226),
    'S' -> Map('B' -> -0.7211965654669841, 'S' -> -0.6658631448798212)
  )
  val emitP: Map[Char, mutable.Map[Char, Double]] = Map(
    'B' -> mutable.Map(),
    'E' -> mutable.Map(),
    'M' -> mutable.Map(),
    'S' -> mutable.Map())
  val states: Array[Char] = Array('B', 'M', 'E', 'S')

  def viterbi(obs: String): mutable.ListBuffer[Char] = {
    val V: mutable.ListBuffer[mutable.Map[Char, Double]] = mutable.ListBuffer(mutable.Map())
    var path: mutable.Map[Char, mutable.ListBuffer[Char]] = mutable.Map()
    for (y: Char <- states) {
      V.head.update(y, startP(y) + emitP(y).getOrElse(obs(0), minDouble))
      path.update(y, mutable.ListBuffer(y))
    }
    for (t <- 1 until obs.length) {
      V.append(mutable.Map())
      val newPath: mutable.Map[Char, mutable.ListBuffer[Char]] = mutable.Map()
      for (y: Char <- states) {
        val emP = emitP(y).getOrElse(obs(t), minDouble)
        val probState: mutable.ListBuffer[(Double, Char)] = mutable.ListBuffer()
        for (y0 <- PrevStatus(y)) {
          probState.append((V(t - 1)(y0) + transP(y0).getOrElse(y, minDouble) + emP, y0))
        }
        val (prob, state): (Double, Char) = probState.max
        V(t)(y) = prob
        newPath(y) = path(state) ++ mutable.ListBuffer(y)
      }
      path = newPath
    }
    val probE = V(obs.length - 1)('E')
    val probS = V(obs.length - 1)('S')
    if (probE > probS) path('E') else path('S')
  }

  def cut_without_dict(clause: String): mutable.ListBuffer[String] = {
    val posList = viterbi(clause)
    var (begin, nextI) = (0, 0)
    val words: mutable.ListBuffer[String] = mutable.ListBuffer()
    for (i <- 0 until clause.length) {
      val pos = posList(i)
      if (pos == 'B') {
        begin = i
      }
      else if (pos == 'E') {
        words.append(clause.slice(begin, i + 1))
        nextI = i + 1
      }
      else if (pos == 'S') {
        words.append(clause.slice(i, i + 1))
        nextI = i + 1
      }
    }
    if (nextI < clause.length) {
      words.append(clause.substring(nextI))
    }
    words
  }
}

测试

object Hello {
  def main(args: Array[String]): Unit = {
    val hmm: HmmTokenizer = new HmmTokenizer
    hmm.emitP('B')('南') = -5.5
    hmm.emitP('M')('南') = -9.9
    hmm.emitP('E')('南') = -9.9
    hmm.emitP('S')('南') = -9.9
    hmm.emitP('B')('门') = -6.6
    hmm.emitP('M')('门') = -9.9
    hmm.emitP('E')('门') = -4.4
    hmm.emitP('S')('门') = -9.9
    hmm.emitP('B')('大') = -9.9
    hmm.emitP('M')('大') = -8.8
    hmm.emitP('E')('大') = -3.3
    hmm.emitP('S')('大') = -9.9
    hmm.emitP('B')('的') = -9.9
    hmm.emitP('M')('的') = -9.9
    hmm.emitP('E')('的') = -9.9
    hmm.emitP('S')('的') = -1.1
    println(hmm.emitP)                          // ListBuffer(B, E, S, B, M, E)
    println(hmm.cut_without_dict("南大的南大门")) // ListBuffer(南大, 的, 南大门)
  }
}

5、HMM分词

import scala.collection.mutable
import scala.math.log10

class Hmm {
  val minDouble: Double = Double.MinValue
  val PrevStatus: Map[Char, String] = Map(
    'B' -> "ES",
    'M' -> "MB",
    'S' -> "SE",
    'E' -> "BM")
  val startP: Map[Char, Double] = Map(
    'B' -> -0.26268660809250016,
    'E' -> minDouble,
    'M' -> minDouble,
    'S' -> -1.4652633398537678)
  val transP: Map[Char, Map[Char, Double]] = Map(
    'B' -> Map('E' -> -0.51082562376599, 'M' -> -0.916290731874155),
    'E' -> Map('B' -> -0.5897149736854513, 'S' -> -0.8085250474669937),
    'M' -> Map('E' -> -0.33344856811948514, 'M' -> -1.2603623820268226),
    'S' -> Map('B' -> -0.7211965654669841, 'S' -> -0.6658631448798212)
  )
  val emitP: Map[Char, mutable.Map[Char, Double]] = Map(
    'B' -> mutable.Map(),
    'E' -> mutable.Map(),
    'M' -> mutable.Map(),
    'S' -> mutable.Map())
  val states: Array[Char] = Array('B', 'M', 'E', 'S')

  def viterbi(obs: String): mutable.ListBuffer[Char] = {
    val V: mutable.ListBuffer[mutable.Map[Char, Double]] = mutable.ListBuffer(mutable.Map())
    var path: mutable.Map[Char, mutable.ListBuffer[Char]] = mutable.Map()
    for (y: Char <- states) {
      V.head.update(y, startP(y) + emitP(y).getOrElse(obs(0), minDouble))
      path.update(y, mutable.ListBuffer(y))
    }
    for (t <- 1 until obs.length) {
      V.append(mutable.Map())
      val newPath: mutable.Map[Char, mutable.ListBuffer[Char]] = mutable.Map()
      for (y: Char <- states) {
        val emP = emitP(y).getOrElse(obs(t), minDouble)
        val probState: mutable.ListBuffer[(Double, Char)] = mutable.ListBuffer()
        for (y0 <- PrevStatus(y)) {
          probState.append((V(t - 1)(y0) + transP(y0).getOrElse(y, minDouble) + emP, y0))
        }
        val (prob, state): (Double, Char) = probState.max
        V(t)(y) = prob
        newPath(y) = path(state) ++ mutable.ListBuffer(y)
      }
      path = newPath
    }
    val probE = V(obs.length - 1)('E')
    val probS = V(obs.length - 1)('S')
    if (probE > probS) path('E') else path('S')
  }

  def cutWithoutDict(clause: String): mutable.ListBuffer[String] = {
    val posList = viterbi(clause)
    var (begin, nextI) = (0, 0)
    val words: mutable.ListBuffer[String] = mutable.ListBuffer()
    for (i <- 0 until clause.length) {
      val pos = posList(i)
      if (pos == 'B') {
        begin = i
      }
      else if (pos == 'E') {
        words.append(clause.slice(begin, i + 1))
        nextI = i + 1
      }
      else if (pos == 'S') {
        words.append(clause.slice(i, i + 1))
        nextI = i + 1
      }
    }
    if (nextI < clause.length) {
      words.append(clause.substring(nextI))
    }
    words
  }
}

class Tokenizer(var w2f: Map[String, Int]) extends Hmm {
  var total: Int = w2f.values.sum
  var maxLen: Int = w2f.keys.map(_.length).max
  val reEng = "[a-zA-Z]+"
  val reNum = "[0-9]+%?|[0-9]+[.][0-9]+%?"

  def calculate(clause: String): mutable.Map[Int, (Double, Int)] = {
    // 句子长度
    val len = clause.length
    // 有向无环图
    val DAG: mutable.Map[Int, mutable.ListBuffer[Int]] = mutable.Map()
    // 词图扫描
    for (head <- 0 until len) {
      val tail = len.min(head + maxLen)
      DAG.update(head, mutable.ListBuffer(head))
      for (mid <- (head + 2) until (tail + 1)) {
        val word = clause slice(head, mid)
        // 词库匹配
        if (w2f.contains(word)) DAG(head).append(mid - 1)
        // 英文匹配
        else if (word.matches(reEng)) DAG(head).append(mid - 1)
        // 数字匹配
        else if (word.matches(reNum)) DAG(head).append(mid - 1)
      }
    }
    // 最短路径
    val route: mutable.Map[Int, (Double, Int)] = mutable.Map(len -> (0.0, 0))
    // 概率对数总值
    val logTotal: Double = log10(total)
    // 动态规划
    for (idx <- Range(len - 1, -1, -1)) {
      var maxStatus: (Double, Int) = (-9e99, 0)
      for (x <- DAG(idx)) {
        val freq: Int = w2f.getOrElse(clause.slice(idx, x + 1), 1)
        val logFreq: Double = log10(freq)
        val lastStatus: Double = route(x + 1)._1
        val status: Double = logFreq - logTotal + lastStatus
        if (status > maxStatus._1) {
          maxStatus = (status, x)
        }
      }
      route.update(idx, maxStatus)
    }
    route
  }

  def cutHmm(clause: String): mutable.ListBuffer[String] = {
    // 句子长度
    val len = clause.length
    // 计算最短路径
    val route: mutable.Map[Int, (Double, Int)] = calculate(clause)
    // 分词列表
    val words: mutable.ListBuffer[String] = mutable.ListBuffer()
    // 根据最短路径取词
    var x: Int = 0
    var buf = ""
    while (x < len) {
      val y = route(x)._2 + 1
      val lWord = clause.slice(x, y)
      if (y - x == 1) {
        buf += lWord
      } else {
        if (buf.nonEmpty) {
          if (buf.length == 1) {
            words.append(buf)
          } else {
            words.appendAll(cutWithoutDict(buf))
          }
          buf = ""
        }
        words.append(lWord)
      }
      x = y
    }
    if (buf.nonEmpty) {
      if (buf.length == 1) {
        words.append(buf)
      } else {
        words.appendAll(cutWithoutDict(buf))
      }
    }
    words
  }

  def cut(clause: String): mutable.ListBuffer[String] = {
    // 句子长度
    val len = clause.length
    // 计算最短路径
    val route: mutable.Map[Int, (Double, Int)] = calculate(clause)
    // 分词列表
    val words: mutable.ListBuffer[String] = mutable.ListBuffer()
    // 根据最短路径取词
    var x: Int = 0
    while (x < len) {
      val y: Int = route(x)._2 + 1
      val lWord: String = clause.slice(x, y)
      words.append(lWord)
      x = y
    }
    words
  }
}

object Hello {
  def main(args: Array[String]): Unit = {
    val w2f = Map("空调" -> 2, "调和" -> 2, "和风" -> 2, "风扇" -> 2, "和" -> 2)
    val tk: Tokenizer = new Tokenizer(w2f)
    tk.emitP('B')('南') = -5.5
    tk.emitP('M')('南') = -9.9
    tk.emitP('E')('南') = -9.9
    tk.emitP('S')('南') = -9.9
    tk.emitP('B')('门') = -6.6
    tk.emitP('M')('门') = -9.9
    tk.emitP('E')('门') = -4.4
    tk.emitP('S')('门') = -9.9
    tk.emitP('B')('大') = -9.9
    tk.emitP('M')('大') = -8.8
    tk.emitP('E')('大') = -3.3
    tk.emitP('S')('大') = -9.9
    tk.emitP('B')('的') = -9.9
    tk.emitP('M')('的') = -9.9
    tk.emitP('E')('的') = -9.9
    tk.emitP('S')('的') = -1.1
    println(tk.cut("南门的大门空调和风扇99元"))
    // ListBuffer(南, 门, 的, 大, 门, 空调, 和, 风扇, 99, 元)
    println(tk.cutHmm("南门的大门空调和风扇99元"))
    // ListBuffer(南门, 的, 大门, 空调, 和, 风扇, 99, 元)
  }
}
Spark机器学习+中文分词实现文本分类 文章目录1、极简样例代码2、完整代码2.1、下载链接2.2、代码架构图(Maven工程)2.3、效果打印 1、极简样例代码 手写中文分词算法 继承org.apache.spark.ml.feature.Tokenizer,重写createTransformFunc Scala手写中文分词算法 继承org.apache.spark.ml.feature.Tokenizer,重写createTransformFunc 中文分词+TFIDF编码+逻辑回归 => 实现文本分类 阅读详情

相关推荐

使用Spark框架中文分词统计

技术 Spark+中文分词 算法 对爬取的网站文章的关键词进行统计,是进行主题分类,判断相似性的一个基础步骤。例如,一篇文章大量出现“风景”和“酒店”之类的词语,那么这篇文章归类为“旅游”类的概率就比较大。而在关于“美食”的文章中,“餐厅”和“美味”等词语出现的频率一般也会比较大。 分词使用语言云http://www.ltp-cloud.com实现对一段中文先进行分词,然后通过Spar

阿里Darker 5059

中文分词框架Hanlp简单案例(scala)

中文分词框架Hanlp简单案例(scala) 背景 在机器学习中,如果需要对中文做自然语言处理,分词的环节必不可少。有很多好用框架 Hanlp就是一个分词框架 案例 <dependency> <groupId>com.hankcs</groupId> <artifactId>hanlp</artifactId> <version>portable-1.7.4&l

xiaohu21的博客 1009

Spark大数据中文分词统计Scala语言工程源码

参考网络资源使用IKAnalyzer分词组件,实现了在Spark框架下使用Scala语言对唐诗宋词等国学经典进行中文分词统计排序的功能,你可以轻松发现唐诗宋词中最常用的词是那几个。

Scala中使用ansj分词库编写spark中文版WordCount

配置环境的链接:spark在Windows10当中部署搭建Scala的使用环境Maven 编写使用的IDE是IntelliJ IDEA Community Edition 安装配置IntelliJ IDEA Community Edition 进入官方网站Download IntelliJ IDEA:The Java IDE,下载社区版的,按照默认配置安装就好,如果是32位的电脑,就勾选32位,64位的勾选64位。打开以后安装插件Scala,这里没有安装的话,需要等进入界面以后再安装。这里是使用Ma

邹九的个人博客 625

Ikanalyzer中文分词统计

实现中文分词,并对结果进行统计,是用IKAnalyzer实现的,很不错!

auboi5 + d435i 使用easy handeye进行标定时,遇到相关问题记录。

解决办法:在easy_handeye默认的 calibrate.launch 文件中move group 的默认值为 "manipulator",但针对每个人的机械臂,这个值需要更改。以aubo_i5为例,需要将其改为"manipulator_i5",或者自己编写launch文件时,传入参数move group的值,便能顺利解决问题!easy_handeye_calibration_server 进程出现崩溃。

weixin_61025092的博客 958

Scala使用Ansj分词

导包 &lt;!-- https://mvnrepository.com/artifact/org.ansj/ansj_seg --&gt; &lt;dependency&gt; &lt;groupId&gt;org.ansj&lt;/groupId&gt; &lt;artifactId&gt;ansj_seg&lt;/artifactId&gt; ...

JarryWangJY的博客 1627

OPC UA 协议详解

OPC UA(统一架构)是新一代工业自动化标准通信协议,替代传统OPC Classic,具有跨平台、高安全性、标准化等优势。基于TCP协议,支持全平台部署,采用面向对象架构组织数据,提供实时读写、事件订阅、历史数据访问等功能。作为工业4.0核心协议,适用于智能制造、数字孪生等场景,能实现多品牌设备统一接入。相比Modbus和MQTT,OPC UA协议更规范安全但复杂度较高,是大型工业集群互联的主流选择。

eastyuxiao的专栏 732

解决Idea编写Scala中文乱码问题

解决idea中文乱码问题

weixin_46047643的博客 2437

避开这些坑!RK3588安卓系统内置输入法的正确姿势(含.mk文件修改指南)

本文详细解析了在RK3588安卓系统定制中预置第三方输入法的完整流程与关键避坑指南。重点涵盖APK签名、Android.mk文件编写、系统默认输入法配置(使用adb ime list命令获取服务名)以及SeLinux策略适配等核心步骤,并指出RK3566/RK3568等兄弟平台的通用性与差异点,帮助开发者实现稳定、深度的系统集成。

tgb34567890的博客 440

从‘眼花缭乱’到‘心中有数’:rs-fMRI统计分析全流程避坑指南(附DPABI操作截图)

本文详细解析了rs-fMRI统计分析的全流程,从质量控制到统计模型选择,再到多重比较校正和结果解读。特别针对DPABI软件操作中的常见陷阱提供实用指南,帮助研究者避免FDR和GRF校正等关键环节的错误,实现从数据混乱到清晰分析的转变。

weixin_33686714的博客 400

Spark实现jieba中文分词(scala)

1.hive原数据: hive> select * from news_noseg limit 10; OK 无锡双龙雷斯特优惠元另赠送礼包搜狐汽车购车咨询热线:转搜狐汽车无锡站编辑:赏车、购车、聊车、玩车搜狐汽车无锡车友群:(此群已满)搜狐汽车无锡车友群:(请加此群)搜狐汽车无锡车友群:(此群已满)搜狐汽车无锡车友群:(此群已满)搜狐汽车无锡车友群:(此群已满)搜狐汽车无锡车友群:(此群已...

qq_43350697的博客 9651

AIGC内容溯源技术:如何追踪AI生成内容的原始来源

本文旨在系统性地介绍AIGC内容溯源的技术体系,帮助读者理解如何追踪AI生成内容的来源。我们将覆盖从基础概念到前沿技术的完整知识链,包括但不限于数字水印、区块链存证、内容指纹等技术方案。文章将从AIGC的基本概念出发,逐步深入探讨各种溯源技术,分析其原理和实现,最后讨论实际应用和未来趋势。AIGC:AI Generated Content,人工智能生成内容内容溯源:追踪数字内容的创作、修改和传播历史数字水印:嵌入在数字内容中的不可见识别信息数字水印:隐藏在内容中的识别信息,像隐形墨水内容指纹。

SuperAGI2025 2073

Spark+Ansj中文分词Scala程序

Spark下四种中文分词工具使用 hanLP ansj jieba fudannlp 推荐使用ansj,速度快而且效果好 另外jieba,hanLP效果也不错。 具体参考 ansj:https://github.com/NLPchina/ansj_seg HanLP:https://github.com/hankcs/HanLP 我的代码如下,加了scala连接mysql数据库查找、插入操作,添加...

1213

ESP32学习笔记03-日志打印

日志分为5个等级。

Car12 1416

【DRAM存储器三十】DDR4介绍-DDR4 SDRAM的主要技术特性之bank group,为什么要搞个group出来?

详述DDR4 bank group的作用

highman110的博客 2139

Spark 大数据中文分词统计 (一) 开发环境搭建

几年前搞BI项目时就听说过大数据技术,当时也买了书,可惜没有认真去学。几年5月份 开始,报名参加王家林老师的大数据蘑菇云行动,才算真正开始学习Spark,学习大数据技术。           网上很多Spark的例子都是经典的WordCount example,可惜都是拿那个英文的readme 文件,分行分词统计,对于中文其实并不适用。所以便想着写一个能处理中文的WordCount, 对一

DumbbellYang的专栏 4789

【38】OpenCV C++实战篇——基于多项式插值的亚像素边缘定位算法

亚像素边缘定位算法实现 本文介绍了一种基于多项式插值的亚像素边缘定位算法,用于提高图像边缘检测的精度。文章首先分析了传统像素级边缘检测方法(如Canny、Sobel)的局限性,指出其在测量应用中的精度不足问题。 算法核心 梯度计算:使用8个方向模板进行卷积运算生成梯度图像 亚像素定位:采用多项式插值方法改进边缘定位精度 实现步骤: 生成8个方向的卷积模板(0°、45°、90°等) 利用filter2D函数计算各方向梯度 通过归一化处理显示梯度图像 代码特点 提供完整的C++实现代码 包含模板生成、梯度计算和

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 1099

Spark下四种中文分词工具使用

Spark下四种中文分词工具使用 hanLP ansj jieba fudannlp 获取四种分词工具 在maven 项目工程下的 pom.xml文件中添加 点击import即可完成对前三种的获取 <dependency> <groupId>org.ansj</groupId> <artifactId>ansj_seg</artifactId>

皮皮虾的博客 1万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Spark + ansj 对大数据量中文进行分词

目前的分词器大部分都是单机服务器进行分词,或者使用hadoop mapreduce对存储在hdfs中大量的数据文本进行分词。由于mapreduce的速度较慢,相对spark来说代码书写较繁琐。本文使用 spark + ansj对存储在hdfs中的中文文本数据进行分词。  首先下载ansj源码文件,下载地址为https://github.com/NLPchina/ansj_seg,同时需要下载

xiao_jun_0820的专栏 6261

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

NLPIR分词教程 Scala版

本文原版为中科院分词系统(NLPIR)JAVA简易教程,由于个人需要,将其修改为Scala版本,供有需求者参考。其中工程结构基于IDEA,目录如下: 将原文CLibrary.java修改为CLibrary.scala,源码如下:import com.sun.jna.{Library, Native}/** * Created by maplejaw on 2017/2/8. */ tra

maplejaw的博客 2132

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

spark scala 用ansj分词

本文编辑于2017.4.15,使用ansj最新的版本5.1.1分词 先要将ansj_seg-5.1.1.jar和nlp-lang-1.7.2.jar加入工程 ansj源码github:https://github.com/NLPchina/ansj_seg ansj下载链接:https://oss.sonatype.org/content/repositories/releases/org/

oZincO的博客 4726

文本汉子字母数字单独分词scala实现

最近做文本去重,使用simhash算法,首先需要对文本进行分词或者分字,两者使用情况稍有偏差,分词我们使用的时基于hanlp的分词算法,本文介绍第二种文本分字算法,连续的英文字母或者数字分为一个字。scala代码如下: package com.test.xtf import scala.collection.mutable.ListBuffer import scala.util.c...

dreamBoat的博客 406

Spark 中文分词

Spark 中文分词 一、导入需要的分词包 import org.ansj.domain.Term import org.ansj.recognition.impl.StopRecognition import org.ansj.splitWord.analysis.ToAnalysis 二、停用词过滤 def filter(stopWords: Array[String]): StopRecog...

weixin_33910460的博客 1189

【Spark学习笔记】Spark下的四种中文分词工具

1. Spark下四种中文分词工具使用 hanLP ansj jieba fudannlp 2. 获取四种分词工具 在maven 项目工程下的 pom.xml文件中添加 点击import即可完成对前三种的获取 <dependency> <groupId>org.ansj</groupId> <artifactI...

不可能打工的博客 1076

大数据(8l)运费分摊

电商场景中,优惠、运费等是以订单为单位进行计算的 若要以商品维度进行分析,就要把优惠、运费等的效果分摊到每个商品 问题来了,由于除法有时除不尽,导致合计有差 Python实现 HIVE实现 Spark实现

ArYe 2240
上一篇: 大数据(7f)比较Python和Scala面向对象
下一篇: CentOS7安装MySQL5.7或MySQL5.6
小基基o_O
博客等级 码龄9年 4414粉丝 467原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小基基o_O

您的鼓励是我创作的巨大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值