検索語句レポートを眺めて“無料”、“求人”、“PDF”、“使い方”……こうした意図がズレている検索語句が延々と費用を溶かす——。
その出血を最短で止める方法が「Nグラム分析」による除外キーワード抽出です。本記事は、上位記事の構成を踏まえつつ、運用現場でそのまま使える手順・基準・テンプレ・自動化まで一気通貫でまとめました。Google 広告/Yahoo!検索広告のどちらにも応用可能。週次運用に組み込めば、CPAの安定化・CTR/品質改善・学習クリーンアップが加速します。
- 1. なぜ除外が効くのか(効果と原理)
- 2. Nグラム分析とは(1-gram/2-gram/3-gram)
- 3. データの準備(出力項目と範囲)
- 4. スプレッドシートでのNグラム生成(ノーコード手順)
- 5. しきい値設計:どれを“除外候補”とみなすか
- 6. 除外の配置とマッチタイプ設計
- 7. 週次オペレーションに落とす(運用フロー)
- 8. 半自動〜全自動化レシピ(そのまま使える雛形)
- 9. まずはコレ:除外“候補”語リスト(出発点)
- 10. よくある失敗と回避策
- 11. KPIの見方(短期と中期)
- 12. “そのまま使える”チェックリスト
- 13. 付録:BigQueryでの簡易Nグラム集計(スペース区切り想定)
- 14. まとめ(勝てる運用のコア)
1. なぜ除外が効くのか(効果と原理)
- 無駄クリック削減:コンバージョンにつながらない意図(情報収集/就職/学術/競合比較/地域外など)を先回りで遮断
- 学習の純度向上:配信アルゴリズムが“良い検索語句”へ学習集中
- CTR・品質スコア改善:不適合なインプレッションを減らす=見かけのCTRも上がりやすい
- 配信予算の再配分:限られた費用を“獲れる語”へ移す
2. Nグラム分析とは(1-gram/2-gram/3-gram)
- N-gram=テキストを連続する N 個の語に分割した集合(例:「歯ブラシ 使い方 比較」→ 1-gram:「歯ブラシ」「使い方」「比較」/2-gram:「歯ブラシ 使い方」「使い方 比較」)
- 狙い:検索語句を単語・連語にほどいて集計し、意図ズレの“共通因子”(無料・安い・中古・求人・とは・pdf・英語等)を発見
- 日本語の注意:日本語はスペースが無い検索が多いため、形態素解析で語を切ると精度が上がります(後述のスクリプト例あり)。
3. データの準備(出力項目と範囲)
対象レポート:検索語句(Search terms)
最低限の列:
- 検索語句(クエリ)
- クリック、表示回数、費用、コンバージョン、コンバージョン値
- キャンペーン/広告グループ/マッチタイプ(分析の切り口に使う)
期間:まずは過去30日(ボリューム不足なら60〜90日)。季節性が強い商材は直近×前年同期間も比較。
4. スプレッドシートでのNグラム生成(ノーコード手順)
4.1 正規化(表記ゆれ吸収)
1列追加して、以下のような置換を施し小文字化・全/半角統一・記号除去を実施。
例:
=LOWER(
TRIM(
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(A2," "," "),
"+","+"),
"‐","-")
)
)
4.2 1-gram(単語)を一気に“縦持ち”へ
Googleスプレッドシートで全行を一列にフラット化:
=TOCOL(SPLIT(TEXTJOIN(" ",TRUE, B2:B), " "), 1)
B2:B
は正規化後の列。- 空白を区切りに全クエリを結合→分割→縦ベクトル化。
頻出語トップを一瞬で出す:
=QUERY(TOCOL(SPLIT(TEXTJOIN(" ",TRUE, B2:B), " "),1),
"select Col1, count(Col1)
where Col1 is not null
group by Col1
order by count(Col1) desc
label count(Col1) 'freq'")
4.3 2-gram/3-gram(連語)
スプレッド関数のみで“スライド窓”を表現するのは煩雑なので、Apps Scriptや軽いPythonを併用するのが実務的(後述サンプル)。
※どうしても関数でやるなら、SPLIT
→TAKE
/DROP
/WRAPROWS
を組み合わせて連結。
5. しきい値設計:どれを“除外候補”とみなすか
おすすめの判定指標(AND/ORで組合せ)
- 費用×0CV:
費用 >= Y
かつCV数 = 0
(例:Y=¥1,000〜¥3,000) - クリック×0CV:
クリック >= X
かつCV数 = 0
(例:X=10〜20) - 出現回数:
N-gram出現回数 >= 3〜5
(アカウント横断なら 5〜10) - 悪性CTR:CTRだけ高いのに0CV/逆に低すぎる(広告/LP意図ズレ疑い)
- CVRの極端な低さ:
CVR <= ターゲットの1/3
- カテゴリ判定:下記“典型パターン”に該当
典型の意図ズレカテゴリ
- 情報探索:「とは」「意味」「使い方」「やり方」「比較」「評判」「口コミ」「ランキング」「おすすめ」「メリット」「デメリット」「安全性」「危険」
- 無料/非商用:「無料」「フリー」「サンプル」「テンプレ」「オープンソース」「ダウンロード」「pdf」「画像」
- 求人/就職:「求人」「募集」「年収」「給料」「社員」「アルバイト」
- 学術/学生:「論文」「研究」「レポート」「卒論」「課題」
- 競合名、他社ブランド(要ポリシー判断)
- 地域外/対象外:「大阪」「海外」「通販不可エリア」「中古」「修理」「返品」
- ターゲット違い:「子供」「赤ちゃん」「介護」「業務用」「法人」「B2B/B2C逆」
- 言語違い:「english」「中文」など(商材次第)
6. 除外の配置とマッチタイプ設計
- 共有の除外リスト(アカウント横断の恒常的ワード):例)「無料」「求人」「pdf」「画像」「とは」など
- キャンペーン固有(商材・地域・訴求に依存する語)
- マッチタイプ
- 完全一致:ピンポイントで強く止める
- フレーズ一致:連語や語尾揺れを広くブロック
- (媒体仕様に依存)部分一致の除外相当の挙動は「広すぎブロック」になりやすいので慎重に
- ブランド/指名語の保護:ブランド名+“トンマナ語”を誤って除外しない(例:「ブランド名 口コミ」が実は高CVR等)
7. 週次オペレーションに落とす(運用フロー)
- データ取得(前週 or 直近30日)
- 正規化→Nグラム集計(1-gram→2-gram→3-gram)
- しきい値フィルタ(費用X・クリックY・出現回数Zなど)
- 人工チェック(ブランド保護/ポリシー/ビジネス的妥当性)
- 除外反映(共有リスト/キャンペーン固有)
- 変更履歴に記録(日時・語・配置・理由・担当)
- 影響確認(翌週のCPA/CTR/検索語句の質)
8. 半自動〜全自動化レシピ(そのまま使える雛形)
8.1 Google スプレッドシート+Apps Script(Nグラム生成)
- 行ごとの検索語句を形態素解析して 1-gram/2-gram/3-gram を発行し、別シートに集計。
/** シートのA列: 検索語句, B〜: クリック/費用/CV 等
* 出力先: シート "ngrams" に [ngram, n, 出現回数] などを書き出し
* 形態素解析は簡易的に「スペース分割→fallback」で実装(日本語は後述Python推奨)
*/
function buildNgrams() {
const ss = SpreadsheetApp.getActive();
const src = ss.getSheetByName('raw');
const dst = ss.getSheetByName('ngrams') || ss.insertSheet('ngrams');
dst.clear();
const rows = src.getRange(2,1,src.getLastRow()-1,1).getValues().map(r => (r[0]||'').toString().trim().toLowerCase());
const map = new Map(); // key: ngram, value: {n:1|2|3, cnt}
const N = [1,2,3];
rows.forEach(q => {
if(!q) return;
// 簡易:スペース分割(未分割の日本語は後述Pythonで)
const toks = q.split(/\s+/).filter(Boolean);
N.forEach(n=>{
for(let i=0; i<=toks.length-n; i++){
const ng = toks.slice(i,i+n).join(' ');
const key = `${n}|${ng}`;
const v = map.get(key) || {n, ng, cnt:0};
v.cnt++;
map.set(key, v);
}
});
});
const out = [['ngram','n','count']];
[...map.values()].sort((a,b)=>b.cnt-a.cnt).forEach(v=> out.push([v.ng, v.n, v.cnt]));
dst.getRange(1,1,out.length,out[0].length).setValues(out);
}
8.2 Google Ads Scripts(検索語句の取得→候補抽出→除外反映)
/** 直近30日の検索語句をGAQLで取得 → シートへ → 別関数でNグラム集計 → しきい値で除外候補を生成 → 共有リスト/キャンペーンへ反映 */
function exportSearchTerms() {
const query = `
SELECT
search_term_view.search_term,
metrics.clicks,
metrics.cost_micros,
metrics.conversions,
campaign.id,
ad_group.id
FROM search_term_view
WHERE segments.date DURING LAST_30_DAYS
`;
const rows = AdsApp.search(query);
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('raw') || ss.insertSheet('raw'); sh.clear();
sh.appendRow(['search_term','clicks','cost','conv','campaign_id','ad_group_id']);
while (rows.hasNext()) {
const r = rows.next();
const cost = r.metrics.costMicros / 1e6;
sh.appendRow([
r.searchTermView.searchTerm,
r.metrics.clicks,
cost,
r.metrics.conversions,
r.campaign.id,
r.adGroup.id
]);
}
}
/** しきい値で“危険Nグラム”を抽出して除外(要:ngramsシートに ngram,count,clicks,cost,conversions 等がある前提) */
function pushNegatives() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('candidates'); // ここにフィルタ済み候補行を用意
const values = sh.getRange(2,1,sh.getLastRow()-1,4).getValues(); // [ngram, scope, matchtype, reason]
const account = AdsApp.currentAccount();
values.forEach(([term, scope, mtype, reason])=>{
if(!term) return;
if(scope === 'shared') {
// 共有除外リストに追加(事前に"NEG_SHARED"というリストを作成しておく)
const lists = AdsApp.negativeKeywordLists().withCondition('Name = "NEG_SHARED"').get();
if(lists.hasNext()) lists.next().addNegativeKeyword(term);
} else {
// キャンペーンID指定スコープ
const campId = scope;
const it = AdsApp.campaigns().withIds([campId]).get();
if(it.hasNext()) {
const c = it.next();
c.createNegativeKeyword(term); // マッチタイプは媒体仕様に依存(必要なら語を"[]"や""で包む等の運用ルールを)
}
}
});
}
※ 実環境に合わせて:アカウントの命名規約・共有除外リスト・許可単語ホワイトリストを先に整備すると安全です。
8.3 Python(日本語の形態素解析で精度UP)
# pip install fugashi
from fugashi import Tagger
tagger = Tagger()
def tokenize(text: str):
return [w.surface for w in tagger(text or '') if w.surface.strip()]
def ngrams(tokens, n=2):
return [' '.join(tokens[i:i+n]) for i in range(len(tokens)-n+1)]
# 例:
q = "電動歯ブラシ 使い方 比較"
toks = tokenize(q) # -> ['電動', '歯', 'ブラシ', '使い方', '比較'] など辞書に依存
bigrams = ngrams(toks, 2)
trigrams = ngrams(toks, 3)
- 形態素で切ってから集計すると、2-gram/3-gramの“意図”がよりはっきり出ます。
9. まずはコレ:除外“候補”語リスト(出発点)
最終判断はビジネス文脈で人工レビューしてください。
- 無料/割引系:無料/フリー/割引/クーポン/安い/格安/最安/中古
- 情報探索:とは/意味/やり方/使い方/仕組み/比較/レビュー/評判/口コミ/おすすめ/ランキング/ブログ
- ドキュメント:pdf/画像/テンプレ/サンプル/例文/マニュアル
- 採用:求人/募集/アルバイト/パート/年収/給料
- アフター/周辺:修理/返品/キャンセル/問い合わせ/電話番号/住所
- 地域外:海外/県名(対象外エリア)
- ターゲット外:子供/赤ちゃん/学生/研究/学術
- 言語:english/中文/韓国語(商圏により)
10. よくある失敗と回避策
- 強すぎる除外で“獲れる尾”を切る:
完全一致除外
を濫用しない。フレーズ除外とホワイトリストで安全運転 - ブランド語の誤除外:ブランド+ネガ語が実は高CVRのケース(例:「ブランド名 口コミ」)→事前にブランド保護表
- PMaxへの影響を軽視:除外制約が強い面・弱い面がある。検索語句の質やブランド保護は別途対処(ブランドセーフ衣装)
- 学習リセット:大規模除外は段階投入し、配信の再学習を観察
- 英数記号・全半角揺れ:正規化を習慣化(小文字化/記号統一/かなカナ統一)
11. KPIの見方(短期と中期)
- 短期(1〜2週):無駄費用・0CVクリックの削減、検索語句の“質”改善
- 中期(3〜6週):CPA安定、CVR上昇、学習の純度向上、有効CPC低下
- レポートの推奨切り口:語種(1/2/3-gram)× デバイス × 時間帯 × 地域 × キャンペーンタイプ
12. “そのまま使える”チェックリスト
導入時
- 共有除外リストを新設(NEG_SHARED など)
- ブランド保護ホワイトリスト定義
- 正規化ルールの合意(小文字化・記号・全半角)
- しきい値(費用・クリック・出現回数)を数値で決める
週次運用
- 直近30日の検索語句を抽出
- Nグラム(1/2/3)で集計
- しきい値で候補抽出→人工レビュー
- 除外反映(共有/キャンペーン)
- 変更履歴と影響(CPA/CTR/CVR)を記録
13. 付録:BigQueryでの簡易Nグラム集計(スペース区切り想定)
-- `project.dataset.search_terms` : columns (query STRING, clicks INT64, cost FLOAT64, conv FLOAT64)
WITH base AS (
SELECT
LOWER(REGEXP_REPLACE(query, r'\s+', ' ')) AS q,
clicks, cost, conv
FROM `project.dataset.search_terms`
),
toks AS (
SELECT
q,
SPLIT(q, ' ') AS arr,
clicks, cost, conv
FROM base
),
unigram AS (
SELECT t,
SUM(clicks) AS clicks, SUM(cost) AS cost, SUM(conv) AS conv, COUNT(*) AS freq
FROM toks, UNNEST(arr) AS t
GROUP BY t
),
bigram AS (
SELECT
ARRAY_TO_STRING( [arr[OFFSET(i)], arr[OFFSET(i+1)]], ' ' ) AS t2,
SUM(clicks) AS clicks, SUM(cost) AS cost, SUM(conv) AS conv, COUNT(*) AS freq
FROM toks, UNNEST(GENERATE_ARRAY(0, ARRAY_LENGTH(arr)-2)) AS i
GROUP BY t2
),
trigram AS (
SELECT
ARRAY_TO_STRING( [arr[OFFSET(i)], arr[OFFSET(i+1)], arr[OFFSET(i+2)]], ' ' ) AS t3,
SUM(clicks) AS clicks, SUM(cost) AS cost, SUM(conv) AS conv, COUNT(*) AS freq
FROM toks, UNNEST(GENERATE_ARRAY(0, ARRAY_LENGTH(arr)-3)) AS i
GROUP BY t3
)
SELECT '1-gram' AS n, t AS ngram, clicks, cost, conv, freq FROM unigram
UNION ALL
SELECT '2-gram', t2, clicks, cost, conv, freq FROM bigram
UNION ALL
SELECT '3-gram', t3, clicks, cost, conv, freq FROM trigram
ORDER BY n, freq DESC;
日本語のスペース無し検索は上記だけでは不十分。MeCab などで事前にトークン配列にして格納すると精度は一気に上がります。
14. まとめ(勝てる運用のコア)
- Nグラム分析=“意図ズレの共通因子”を見つける顕微鏡。
- 明確なしきい値と人間の最終判断をセットに。
- 共有除外×キャンペーン固有の二段構えで安全かつ強力に。
- スクリプト化で毎週の作業を10分以内へ。
この流れを習慣化すれば、検索語句の質がみるみる改善し、CPAの“底”が固まります。今日から運用に組み込んでいきましょう。