美文网首页R炒面
110-文本分析之文本特征提取

110-文本分析之文本特征提取

作者: wonphen | 来源:发表于2022-10-05 16:14 被阅读0次

    参考:《文本数据挖掘——基于R语言》

    1、基本特征提取

    基本特征包括:字符的数量、句子的数量、每个词的长度,标点符号的数量等。

    # 只能分析英文
    p_load(textfeatures)
    
    txt <- "1000pcs 8*32mm 0.5ml Plastic Centrifuge Tube Test Tubing Vial Clear Plastic Container Home Garden Storage Bottles。1000pcs 6*22mm 0.2ml Plastic Bottles Gardening Storage Container Transparent Plastic Vials PCR Centrifuge Tube"
    # sentiment参数能够自动进行情感分析,word_dims则可以使用词袋模型对文本进行向量化,normalize参数可以对数据按列进行归一化。全部关闭
    textfeatures(txt, sentiment = F, word_dims = F, normalize = F,
                 verbose = F) %>%
      # 显示所有结果
      print(width = Inf)
    
    ## # A tibble: 1 × 29
    ##   n_urls n_uq_urls n_hashtags n_uq_hashtags n_mentions n_uq_mentions n_chars
    ##    <int>     <int>      <int>         <int>      <int>         <int>   <int>
    ## 1      0         0          0             0          0             0     196
    ##   n_uq_chars n_commas n_digits n_exclaims n_extraspaces n_lowers n_lowersp
    ##        <int>    <int>    <int>      <int>         <int>    <int>     <dbl>
    ## 1         35        0       18          0             0      147     0.751
    ##   n_periods n_words n_uq_words n_caps n_nonasciis n_puncts n_capsp
    ##       <int>   <int>      <int>  <int>       <int>    <int>   <dbl>
    ## 1         3      29         20     26           0        2   0.137
    ##   n_charsperword n_first_person n_first_personp n_second_person
    ##            <dbl>          <int>           <int>           <int>
    ## 1           6.57              0               0               0
    ##   n_second_personp n_third_person n_tobe n_prepositions
    ##              <int>          <int>  <int>          <int>
    ## 1                0              0      0              0
    

    ● n_urls:文本中包含的URL的数量。
    ● n_uq_urls:文本中包含唯一URL的数量(本例中的计算结果并不准确)。
    ● n_chars:总字符数量;
    ● n_commas:逗号的数量;
    ● n_lowers:小写字符数量;
    ● n_lowersp:小写字符比例;
    ● n_words:单词总数量;
    ● n_uq_words:唯一单词的数量;
    ● n_first_person:第一人称单数单词的数量;
    ● n_second_personp:第二人称复数单词的数量;
    ● n_prepositions:介词的数量。

    2、基于TF-IDF的特征提取

    TF-IDF就是词频TF与逆文档频率IDF的乘积,它背后的思想是:词语的重要性与它在文件中出现的次数成正比,但同时会随着它在语料库中出现的频率成反比。

    library(pacman)
    p_load(dplyr, stringr, purrr)
    

    2.1 读取数据

    随便文本代替即可,包括两列,一列为文档名或编号,一列为文本内容。

    storagebottles <- read.csv("dataset/ali/storagebottles0905.csv", 
                               header = F) %>% 
      set_names(c("sku_name", "sku_price", "sku_sale_volume", "sku_score",
                  "sku_ship", "sku_isNewin", "sku_isPromotion", 
                  "sku_isTopselling", "shop_name", "sku_link", "category4")) %>%
      distinct(.keep_all = T)
    
    storagebottles <- storagebottles %>% 
      filter(!is.na(sku_name)) %>%
      filter(str_detect(sku_price, "^US")) %>% 
      filter(str_detect(sku_link, "aliexpress")) %>% 
      filter(str_detect(sku_sale_volume, "sold")) %>% 
      mutate(category = "home",
             category2 = "Home Storage",
             category3 = "Storage Bottles & Jars")  %>% 
      mutate(sku_id = str_extract(sku_link, "\\d{16}"),
             sku_link = paste0("http:", sku_link)) %>% 
      mutate(sku_id = as.character(sku_id)) %>% 
      arrange(sku_sale_volume) %>% 
      group_by(sku_id, .drop = T) %>% 
      slice_tail(n=1) %>% 
      ungroup()
    
    df <- select(storagebottles, sku_id, sku_name)
    
    count(df, sku_id, stem) %>% 
      bind_tf_idf(term = stem, 
                  document = sku_id, 
                  n = n)
    
    ## # A tibble: 19,586 × 6
    ##    sku_id           stem          n     tf   idf tf_idf
    ##    <chr>            <chr>     <int>  <dbl> <dbl>  <dbl>
    ##  1 2251801564728378 0.5ml         1 0.0588 5.70  0.335 
    ##  2 2251801564728378 1000pcs       1 0.0588 6.40  0.376 
    ##  3 2251801564728378 32mm          1 0.0588 7.09  0.417 
    ##  4 2251801564728378 8             1 0.0588 4.89  0.288 
    ##  5 2251801564728378 bottl         1 0.0588 0.542 0.0319
    ##  6 2251801564728378 centrifug     1 0.0588 4.79  0.282 
    ##  7 2251801564728378 clear         1 0.0588 2.29  0.135 
    ##  8 2251801564728378 contain       1 0.0588 0.549 0.0323
    ##  9 2251801564728378 garden        1 0.0588 5.48  0.322 
    ## 10 2251801564728378 home          1 0.0588 2.60  0.153 
    ## # … with 19,576 more rows
    

    2.2 词嵌入

    2.2.1 基于BOW(词袋模型)

    这种方法是信息的简化表示,把文本表示为词语的集合,不考虑文中的语法或者词序,但是能够对内容的多样性进行记录。

    可以使用词频或者使用TF-IDF进行表征:

    count(df, sku_id, stem) %>% 
      bind_tf_idf(term = stem, 
                  document = sku_id, 
                  n = n) %>% 
      cast_dfm(document = sku_id,
               term = stem,
               value = tf_idf)
    
    ## Document-feature matrix of: 1,198 documents, 1,641 features (99.00% sparse) and 0 docvars.
    ##                   features
    ## docs                   0.5ml   1000pcs      32mm         8      bottl
    ##   2251801564728378 0.3354185 0.3761919 0.4169652 0.2877167 0.03186020
    ##   2251801564729229 0         0.4263508 0         0         0.03610822
    ##   2251832228713647 0         0         0         0         0.02850649
    ##   2251832295192632 0         0         0         0         0         
    ##   2251832346856028 0         0         0         0         0         
    ##   2251832357989488 0         0         0         0         0         
    ##                   features
    ## docs               centrifug     clear    contain    garden      home
    ##   2251801564728378 0.2815190 0.1348599 0.03228370 0.3222924 0.1529278
    ##   2251801564729229 0.3190549 0         0.03658819 0.3652647 0        
    ##   2251832228713647 0         0         0          0         0        
    ##   2251832295192632 0         0         0          0         0        
    ##   2251832346856028 0         0         0.03430143 0         0        
    ##   2251832357989488 0         0         0.05226884 0         0        
    ## [ reached max_ndoc ... 1,192 more documents, reached max_nfeat ... 1,631 more features ]
    

    text2vec包对词袋模型的高性能运算提供了强大的实现方法:

    p_load(text2vec)
    
    df <- select(storagebottles, sku_id, sku_name)
    
    # 预处理及分词
    it <- itoken(df$sku_name,
                 # 预处理函数定义,转换为小写
                 preprocessor = tolower,
                 # 分词器定义,使用空格分割
                 tokenizer = word_tokenizer,
                 ids = df$sku_id,
                 # 是否显示进度条
                 progressbar = F)
    
    # 构建词汇表
    vocab <- create_vocabulary(it)
    
    # 文本向量化
    vec <- vocab_vectorizer(vocab)
    
    # 创建DTM矩阵,顺便测试时间
    system.time({
      dtm_train <- create_dtm(it = it,
                              vectorizer = vec)
    })
    
    ## 用户 系统 流逝 
    ## 0.00 0.03 0.03
    

    2.2.2 基于word2vec

    word2vec是一组用于生成词向量的自然语言处理工具,主要是基于双层神经网络,经过训练后可以为单词生成一个向量空间,为每一个单词都分配一个向量。在生成的向量空间中,意思越相近的单词向量之间的距离越小,反之则越大。word2vec有两种模式,分别是CBOW和skip-gram。

    p_load(word2vec)
    
    mod <- word2vec(x = df$sku_name,
                    # 输出向量的维度
                    dim = 10,
                    # 迭代次数
                    iter = 20,
                    # 使用COBW模型还是skip-gram模型
                    type = "cbow")
    
    # 转换为矩阵
    emb <- as.matrix(mod)
    head(emb)
    
    ##               [,1]       [,2]        [,3]       [,4]       [,5]       [,6]
    ## Beads   -1.9400728 -0.0888407 -0.08349484 -1.2562962 -0.2697616 -1.8421835
    ## Weekly  -1.1608911 -0.4651599 -0.25436968 -1.4303011 -0.9386142 -1.7998306
    ## PVC      0.3128605  0.8036703  0.09885665 -2.0803137  0.7472407 -0.4748393
    ## Foaming -0.7814559 -0.2095719  0.88936573  0.2705340 -0.1661042 -1.4170694
    ## Flat     0.4067485 -0.7098307 -0.97712469 -0.8143641  0.9589156 -0.3076381
    ## Herbs   -0.7869626  1.7579030  0.37374184 -1.6308879 -1.1516812 -0.4863058
    ##               [,7]       [,8]        [,9]      [,10]
    ## Beads   -0.5022707  0.6688779  0.68726629 0.06747537
    ## Weekly  -0.5683426  1.3080628  0.29630077 0.28856692
    ## PVC     -1.0187222  1.5673116  0.50875384 0.61791813
    ## Foaming -2.1313248  0.8421388 -1.07562840 0.19196655
    ## Flat     0.2689168  1.7321179  0.43238384 1.85447288
    ## Herbs   -0.1345760 -0.6410958  0.05552098 1.22308218
    
    # 与container最接近的5个词
    predict(mod, c("plastic"), type = "nearest", top_n = 5)
    
    ## $plastic
    ##     term1       term2 similarity rank
    ## 1 plastic transparent  0.9843451    1
    ## 2 plastic       empty  0.9740745    2
    ## 3 plastic       small  0.9626620    3
    ## 4 plastic     perfume  0.9494769    4
    ## 5 plastic      bottle  0.9455841    5
    
    # 模型保存,path为自定义路径
    write.word2vec(mod, file = path)
    
    # 模型读取
    read.word2vec(path)
    

    2.2.3 基于Glove

    它是一种用于获取词向量表示的无监督学习算法,与BOW相似,都是基于词之间共现关系,但是这个算法能够保留基于上下文关系保留更多的语境信息,能够取得更好的向量化效果。

    p_load(text2vec)
    
    tokens <- df %>% 
      # 使用空格分词
      mutate(sku_name = tolower(sku_name)) %>% 
      mutate(token = space_tokenizer(sku_name)) %>% 
      pull(token)
    
    # 设置迭代器
    it <- itoken(df$sku_name, # 这个是语料
                 # 转为小写
                 preprocessor = tolower, 
                 # 使用空格分词
                 tokenizer = space_tokenizer,   
                 ids = df$sku_id,
                 progressbar = F)
    # 创建词汇表,加载停止词
    vocab <- create_vocabulary(it, stopwords = tm::stopwords())
    
    # 保留出现5次以上的词
    vocab <- prune_vocabulary(vocabulary = vocab,
                              term_count_min = 5L)
    # 形成语料文件
    vectorizer <- vocab_vectorizer(vocabulary = vocab)
    
    # 构建DTM矩阵,窗口宽度设置为5
    tcm <- create_tcm(it, vectorizer, skip_grams_window = 5L)
    
    # 设置词向量维度设为50
    glove <- GlobalVectors$new(rank = 50,
                               # 权重为最大共现数
                               x_max = 10)
    # SDG迭代次数为10
    wv_main <- glove$fit_transform(x = tcm, n_iter = 10, 
                                   convergence_tol = 0.01,
                                   # 不加参数默认所有线程并行计算
                                   n_threads = 4)
    
    ## INFO  [15:27:30.119] epoch 1, loss 0.3156
    ## INFO  [15:27:30.137] epoch 2, loss 0.1382
    ## INFO  [15:27:30.155] epoch 3, loss 0.1033
    ## INFO  [15:27:30.172] epoch 4, loss 0.0841
    ## INFO  [15:27:30.190] epoch 5, loss 0.0708
    ## INFO  [15:27:30.208] epoch 6, loss 0.0610
    ## INFO  [15:27:30.226] epoch 7, loss 0.0534
    ## INFO  [15:27:30.243] epoch 8, loss 0.0473
    ## INFO  [15:27:30.260] epoch 9, loss 0.0423
    ## INFO  [15:27:30.277] epoch 10, loss 0.0382
    
    wv_content <- glove$components
    dim(wv_content)
    
    ## [1]  50 538
    
    # 最终结果
    word_vectors <- wv_main + t(wv_content)
    

    2.2.4 基于fastText

    可以完成词嵌入和文本分类等任务。与GloVe类似,它也是word2vec的一种扩展,但它利用了神经网络对词语进行向量化,能够对字符级的特征进行学习。
    fastText 模型架构和 Word2Vec 中的 CBOW 模型很类似。不同之处在于,fastText 预测标签,而 CBOW 模型预测中间词。

    举例来说:fastText能够学会“男孩”、“女孩”、“男人”、“女人”指代的是特定的性别,并且能够将这些数值存在相关文档中。然后,当某个程序在提出一个用户请求(假设是“我女友现在在儿?”),它能够马上在fastText生成的文档中进行查找并且理解用户想要问的是有关女性的问题。

    p_load(text2vec)
    # 一直报错,原因是R4.2.1,需要安装rtools4.2,否则安装会报错
    p_load_gh("pommedeterresautee/fastrtext")
    
    
     # 生成文本
    txt <- df %>% 
      pull(sku_name) %>% 
      tolower() %>% 
      str_remove_all("[:punct:]")
    
    # 构建文本文档,执行向量化
    tmp_file_txt <- tempfile()
    tmp_file_model <- tempfile()
    
    writeLines(txt, con = tmp_file_txt)
    execute(commands = c("skipgram", "-input", tmp_file_txt,
                         "-output", tmp_file_model,
                         "-verbose", 1))
    
    ## 
    Read 0M words
    ## Number of words:  548
    ## Number of labels: 0
    ## 
    Progress: 100.0% words/sec/thread:   34165 lr:  0.000000 avg.loss:  3.049489 ETA:   0h 0m 0s
    
    # 载入模型
    model <- load_model(tmp_file_model)
    
    # 获取字典
    dict <- get_dictionary(model)
    
    # 获得词向量
    word_vectors <- get_word_vectors(model)
    
    # 释放内存
    unlink(tmp_file_txt)
    unlink(tmp_file_model)
    rm(model)
    gc()
    
    ##           used  (Mb) gc trigger  (Mb) max used  (Mb)
    ## Ncells 3840040 205.1    6683084 357.0  6683084 357.0
    ## Vcells 7261552  55.5   14786712 112.9 10146316  77.5
    

    execute()可以输入的函数:
    以下参数是强制性的:
    -input 训练文件路径
    -output 输出文件路径
    以下参数是可选的:
    -verbose 详细级别,默认2

    字典选项:
    -minCount 最少单词出现次数,默认5
    -minCountLabel 最少标签出现次数,默认0
    -wordNgrams ngram最大单词数,默认1
    -bucket 存储体数量,默认2000000
    -minn ngram最小字符长度,默认3
    -maxn ngram最大字符长度,默认6
    -t 采样阈值,默认0.0001
    -label 标签前缀,默认_label_

    以下训练参数是可选的:
    -lr 学习速度,默认0.05
    -lrUpdateRate 学习速度的更新率,默认100
    -dim 词矩阵维度,默认100
    -ws 上下文窗口大小,默认5
    -epoch 时期数,默认5
    -neg 负采样数,默认5
    -loss 损失函数 {ns, hs, softmax},默认ns
    -thread 线程数,默认12
    -pretrainedVectors 用于监督的预训练词向量,默认为空
    -saveOutput 是否保存输出参数,默认0

    以下量化参数可选:
    -cutoff 要保留的单词和 ngram 的数量,默认0
    -retrain 如果应用了截止,则微调嵌入,默认0
    -qnorm 分别量化范数,默认0
    -qout 量化分类器,默认0
    -dsub 每个子向量的大小,默认2

    3、文档向量化

    对文档进行分词,然后利用获得的词向量,用文档中所有词汇向量进行加和,然后再除以一个标量来获得文档表示向量。

    p_load(textTinyR, text2vec)
    
    tokens <- df %>% 
      mutate(sku_name = tolower(sku_name)) %>% 
      mutate(token = space_tokenizer(sku_name)) %>% 
      pull(token)
    
    it <- itoken(tokens, progressbar = F)
    vocab <- create_vocabulary(it)
    vocab <- prune_vocabulary(vocab, term_count_min = 5L)
    
    vectorizer <- vocab_vectorizer(vocab)
    tcm <- create_tcm(it, vectorizer, skip_grams_window = 5L)
    
    glove <- GlobalVectors$new(rank = 50, x_max = 10)
    # SDG迭代次数为10
    wv_main <- glove$fit_transform(x = tcm, n_iter = 10)
    
    ## INFO  [15:27:41.400] epoch 1, loss 0.3118
    ## INFO  [15:27:41.417] epoch 2, loss 0.1380
    ## INFO  [15:27:41.433] epoch 3, loss 0.1033
    ## INFO  [15:27:41.450] epoch 4, loss 0.0842
    ## INFO  [15:27:41.470] epoch 5, loss 0.0710
    ## INFO  [15:27:41.486] epoch 6, loss 0.0613
    ## INFO  [15:27:41.504] epoch 7, loss 0.0537
    ## INFO  [15:27:41.520] epoch 8, loss 0.0476
    ## INFO  [15:27:41.537] epoch 9, loss 0.0427
    ## INFO  [15:27:41.553] epoch 10, loss 0.0385
    
    wv_content <- glove$components
    dim(wv_content)
    
    ## [1]  50 548
    
    # 最终结果
    word_vectors <- wv_main + t(wv_content)
    
    # 保存词向量
    write.table(word_vectors, file = "wv.txt", col.names = F)
    
    # 转化清洗
    readLines("wv.txt") %>% 
      str_remove_all("\\\"") %>% 
      writeLines("wv.txt")
    
    # 提取需要向量化的文档
    tok_text <- tokens
    
    # 文档向量化
    init <- Doc2Vec$new(token_list = tok_text,
                        word_vector_FILE = "wv.txt")
    
    # method参数使用了“sum_sqrt”,它表示文档向量会对词汇向量先进行简单加和获得一个新的向量
    # INITIAL_WORD_VECTOR,然后对这个向量求平方和再开方得到一个标量k,
    # 最后INITIAL_WORD_VECTOR除以k就是最后的文档向量。
    out <- init$doc2vec_methods(method = "sum_sqrt")
    
    # 删除向量化词汇表
    unlink("wv.txt")
    

    相关文章

      网友评论

        本文标题:110-文本分析之文本特征提取

        本文链接:https://www.haomeiwen.com/subject/okvjartx.html