以下のチェックをする前に,Wordのdocxファイルは docx2txt を使ってテキストに直しておく:
for x in *.docx; do docx2txt.pl $x; done
それ以外のものも UTF-8 テキストに変換しておく。
コピペのチェックが流行りなので,やってみた。ただし,ネット検索するのでなく,相互剽窃のチェックだけである。Rのstringdistパッケージを使う。
# レポート(テキストファイル)のファイル名(tmp/*.txt の場合)
names = dir("tmp", "*.txt", full.names=TRUE)
library(stringdist)
n = length(names)
s = character(n)
for (i in 1:n) {
s[i] = readChar(names[i], 2000) # 頭2000文字分読む(Unicode)
}
for (i in 1:(n-1)) {
for (j in (i+1):n) {
ni = nchar(s[i])
nj = nchar(s[j])
d = stringdist(s[i], s[j], method='lv') - abs(ni - nj)
if (d < 100) {
cat(names[i], names[j], ni, nj, d, "\n")
}
}
}
上ではLevenshtein距離から文字数の差の絶対値を引いたものを使っている。どのような指標が良いかは考え中。
[追記] i をもとにして j を作った場合,j のどれくらいの割合が i かを示す量として,(max(ni, nj) - d) / nj
が良いかもしれない。
文字列 $x$ の Kolmogorov complexity(ざっくり言えば,データ圧縮後の最小ファイルサイズ)を $K(x)$ とし,文字列 $x$,$y$ をつなぎ合わせた文字列を $x+y$ とすると,
\[ \max(K(x),K(y)) \leq K(x+y) \leq K(x) + K(y) \]が成り立つ。中辺 $K(x+y)$ が左辺に近いほど $x$,$y$ は似ている。これを使ってレポートの類似性を調べることができる(かもしれない)。$K(x)$ の代わりに gzip
(オプション -9
)で圧縮後のファイルサイズを使う:
K = numeric(n)
for (i in 1:n) {
K[i] = as.numeric(system(paste("cat", names[i], "| gzip -9 -c | wc -c"), intern=T))
}
for (i in 1:(n-1)) {
for (j in (i+1):n) {
Kij = as.numeric(system(paste("cat", names[i], names[j], "| gzip -9 -c | wc -c"), intern=T))
# Kij が max(K[i],K[j]) と K[i]+K[j] のどちらに近いか調べて報告
}
}
この種のものは2002年に Language Trees and Zipping というペーパーが(よりによって)Physical Review Letters に掲載されてからちょっとだけ流行した。
Last modified: