ts-content-based-recommender
Version:
A TypeScript-based content-based recommender with multilingual support (Japanese & English). Forked from content-based-recommender.
127 lines • 4.85 kB
JavaScript
import * as sw from 'stopword';
/**
* 英語専用トークンフィルタークラス
* ストップワード除去、重複除去、長さフィルタリング、N-gram対応等を行います
*/
export class EnglishTokenFilter {
/**
* コンストラクタ
* @param options フィルターオプション
*/
constructor(options = {}) {
this.options = {
removeDuplicates: options.removeDuplicates ?? true,
removeStopwords: options.removeStopwords ?? true,
customStopWords: options.customStopWords ?? [],
minTokenLength: options.minTokenLength ?? 1,
allowedPos: options.allowedPos ?? ['名詞', '動詞', '形容詞'] // 日本語用なので英語では使用しない
};
}
/**
* トークン配列をフィルタリングする
* @param tokens フィルタリング対象のトークン配列
* @returns フィルタリング済みトークン配列
*/
filter(tokens) {
let filteredTokens = tokens;
// 長さフィルタリング
if (this.options.minTokenLength > 1) {
filteredTokens = this._filterByLength(filteredTokens);
}
// ストップワード除去
if (this.options.removeStopwords) {
filteredTokens = this._removeStopwords(filteredTokens);
}
// 重複除去
if (this.options.removeDuplicates) {
filteredTokens = this._removeDuplicates(filteredTokens);
}
return filteredTokens;
}
/**
* N-gram対応フィルタリング(英語用)
* ストップワードを含むN-gramを除去します
* @param tokens トークン配列
* @returns フィルタリング済みトークン配列
*/
filterWithNgrams(tokens) {
let filteredTokens = tokens;
// 長さフィルタリング
if (this.options.minTokenLength > 1) {
filteredTokens = this._filterByLength(filteredTokens);
}
// N-gramのストップワードフィルタリング
if (this.options.removeStopwords) {
filteredTokens = this._filterNgramsWithStopwords(filteredTokens);
}
// 重複除去
if (this.options.removeDuplicates) {
filteredTokens = this._removeDuplicates(filteredTokens);
}
return filteredTokens;
}
/**
* 長さによるフィルタリング
* @param tokens トークン配列
* @returns フィルタリング済みトークン配列
*/
_filterByLength(tokens) {
return tokens.filter(token => token.length >= this.options.minTokenLength);
}
/**
* ストップワード除去(英語用)
* @param tokens トークン配列
* @returns ストップワード除去済みトークン配列
*/
_removeStopwords(tokens) {
// stopwordライブラリを使用した後、カスタムストップワードも除去
let filteredTokens = sw.removeStopwords(tokens);
if (this.options.customStopWords.length > 0) {
const customStopWords = new Set([
...EnglishTokenFilter.DEFAULT_STOPWORDS,
...this.options.customStopWords
]);
filteredTokens = filteredTokens.filter(token => !customStopWords.has(token));
}
return filteredTokens;
}
/**
* N-gramのストップワードフィルタリング(英語用)
* @param tokens トークン配列
* @returns フィルタリング済みトークン配列
*/
_filterNgramsWithStopwords(tokens) {
const filteredTokens = [];
for (const token of tokens) {
if (token.includes('_')) {
// N-gramの場合、ストップワードを含むかチェック
const tokenParts = token.split('_');
if (tokenParts.length === sw.removeStopwords(tokenParts).length) {
filteredTokens.push(token);
}
}
else {
// ユニグラムの場合、通常のストップワード除去
const removed = sw.removeStopwords([token]);
if (removed.length > 0) {
filteredTokens.push(token);
}
}
}
return filteredTokens;
}
/**
* 重複除去
* @param tokens トークン配列
* @returns 重複除去済みトークン配列
*/
_removeDuplicates(tokens) {
return Array.from(new Set(tokens));
}
}
/** 英語デフォルトストップワード */
EnglishTokenFilter.DEFAULT_STOPWORDS = [
'the', 'is', 'at', 'which', 'on', 'a', 'an', 'and', 'or', 'but',
'in', 'with', 'to', 'for', 'of', 'as', 'by'
];
//# sourceMappingURL=EnglishTokenFilter.js.map