2017-10-31 27 views

答えて

2

このクエリは、5つの段階で動作します:。

  1. は、私が興味のすべてのredditの記事を取得する(一部のHTML UNESCAPE、LOWER、文字だけと')の単語を正規化。それらの単語を配列に分割します。
  2. 各文書の各単語のtf(単語頻度)を計算する - 各文書に表示される回数を、その文書の単語の数と比較してカウントします。
  3. 各単語について、それを含むドキュメントの数を計算します。
  4. (3)から、idf(逆文書頻度)を得る:単語を含む文書の逆数、単語の総数を単語を含む文書の数で除算した後、対数を取るその商の "
  5. tf-idfを得るためにtf * idfを掛けます。

このクエリは、得られた値をチェーンの上に渡すことで、1回のパスでこれを行うことができます。

#standardSQL 
WITH words_by_post AS (
    SELECT CONCAT(link_id, '/', id) id, REGEXP_EXTRACT_ALL(
    REGEXP_REPLACE(REGEXP_REPLACE(LOWER(body), '&', '&'), r'&[a-z]{2,4};', '*') 
     , r'[a-z]{2,20}\'?[a-z]+') words 
    , COUNT(*) OVER() docs_n 
    FROM `fh-bigquery.reddit_comments.2017_07` 
    WHERE body NOT IN ('[deleted]', '[removed]') 
    AND subreddit = 'movies' 
    AND score > 100 
), words_tf AS (
    SELECT id, word, COUNT(*)/ARRAY_LENGTH(ANY_VALUE(words)) tf, ARRAY_LENGTH(ANY_VALUE(words)) words_in_doc 
    , ANY_VALUE(docs_n) docs_n 
    FROM words_by_post, UNNEST(words) word 
    GROUP BY id, word 
    HAVING words_in_doc>30 
), docs_idf AS (
    SELECT tf.id, word, tf.tf, ARRAY_LENGTH(tfs) docs_with_word, LOG(docs_n/ARRAY_LENGTH(tfs)) idf 
    FROM (
    SELECT word, ARRAY_AGG(STRUCT(tf, id, words_in_doc)) tfs, ANY_VALUE(docs_n) docs_n 
    FROM words_tf 
    GROUP BY 1 
), UNNEST(tfs) tf 
)  


SELECT *, tf*idf tfidf 
FROM docs_idf 
WHERE docs_with_word > 1 
ORDER BY tfidf DESC 
LIMIT 1000 

enter image description here

+1

私は間違っているかもしれませんが、どういうわけか、 'r '[az] {2,20} \'?[az] * ''ではなく' REGEXP_EXTRACT_ALL'で 'r' [az] {2、 20} \ '?[az] +' –

+0

@MikhailBerlyantをチェックしていただきありがとうございます!違いは、単語が '' 'で終わることができるでしょうか? –

+1

これはまさに私が思ったことです。コメントに「abc」のような言葉があります。o) –

1

スタックオーバーフローのデータセットバージョン:前の回答対

#standardSQL 
WITH words_by_post AS (
    SELECT id, REGEXP_EXTRACT_ALL(
     REGEXP_REPLACE(
     REGEXP_REPLACE(
     REGEXP_REPLACE(
     LOWER(CONCAT(title, ' ', body)) 
     , r'&', '&') 
     , r'&[a-z]*;', '') 
     , r'<[= \-:a-z0-9/\."]*>', '') 
     , r'[a-z]{2,20}\'?[a-z]+') words 
    , title, body 
    , COUNT(*) OVER() docs_n 
    FROM `bigquery-public-data.stackoverflow.posts_questions` 
    WHERE score >= 150 
), words_tf AS (
    SELECT id, words 
    , ARRAY(
    SELECT AS STRUCT w word, COUNT(*)/ARRAY_LENGTH(words) tf 
    FROM UNNEST(words) a 
    JOIN (SELECT DISTINCT w FROM UNNEST(words) w) b 
    ON a=b.w 
    WHERE w NOT IN ('the', 'and', 'for', 'this', 'that', 'can', 'but') 
    GROUP BY word ORDER BY word 
    ) tfs 
    , ARRAY_LENGTH((words)) words_in_doc 
    , docs_n 
    , title, body 
    FROM words_by_post 
    WHERE ARRAY_LENGTH(words)>20 
), docs_idf AS (
    SELECT *, LOG(docs_n/docs_with_word) idf 
    FROM (
    SELECT id, word, tf.tf, COUNTIF(word IN UNNEST(words)) OVER(PARTITION BY word) docs_with_word, docs_n 
    , title, body 
    FROM words_tf, UNNEST(tfs) tf 
) 
)  


SELECT id, ARRAY_AGG(STRUCT(word, tf*idf AS tf_idf, docs_with_word) ORDER BY tf*idf DESC) tfidfs 
# , ANY_VALUE(title) title, ANY_VALUE(body) body # makes query slower 
FROM docs_idf 
WHERE docs_with_word > 1 
GROUP BY 1 

改良:一つ少ないGROUP BYデータセット全体では、より高速なクエリの実行を支援し、必要とされています。

関連する問題