わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

全国学力テストの新聞各記事から「位」を見比べる

昨日,今年の全国学力テストの結果が公表され,新聞各紙も記事にしています.
よく知られているように,これは順位付け(序列化)を行うべきものではありませんが,最初に見かけた記事で,順位を細かく書いていたこともあって,「位」という字の使い方で,新聞のスタンスが比較できるのではないか,と思うようになりました.
思い立ったが吉日.Rubyでコーディングです.

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

# keyword-detector.rb

class KeywordDetector
  def initialize(t)
    @text_orig = t       # 対象テキスト(空白処理前)
    @context_length = 10 # KWIC表示における前後の最大字数
    @keyword = ""      # 検索語
  end
  
  def setup_text
    @text = @text_orig.gsub(/\s/m, "") # 対象テキスト(空白除去)
    @text_len = @text.split(//).length # 字数
    @freq = 0                          # 検索語の出現回数
  end
  private :setup_text
  
  def scan
    @text.scan(/#{@keyword}/) do |s|
      @freq += 1
      pre, post = $`, $'
      
      # 前後の文字列を切り縮める
      pre_a = pre.split(//)
      if pre_a.length > @context_length
        pre = pre_a[-@context_length, @context_length].join("")
      end
      post_a = post.split(//)
      if post_a.length > @context_length
        post = post_a[0, @context_length].join("")
      end

      # KWIC出力
      puts "#{pre} #{@keyword} #{post}"
    end
  end
  private :scan

  def start
    setup_text
    puts "字数(空白除く): #{@text_len}"
    scan
    puts "\"#{@keyword}\"の出現回数: #{@freq}"
  end
end

if __FILE__ == $0
  # 「__END__」以下のテキストデータを,「#」を区切り文字として分割し,
  # それぞれに対して検索語を見つける.
  text_all = DATA.read
  text_all.split(/\#/m).each do |text|
    next if /\A\s*\z/ =~ text
    if /^.*?$/ =~ text
      head, body = $&, $'
      puts "\# #{head}"
      KeywordDetector.new(body).start
    end
  end
#  KeywordDetector.new(DATA.read).start
end

__END__
# http://www.yomiuri.co.jp/national/news/20090827-OYT1T00883.htm
文部科学省は27日、第3回全国学力テストの結果を公表した。
[略]
 中学生の国語・数学のBは、大阪府とともに、沖縄、高知県が昨年に続いてワースト3だった。
# http://www.asahi.com/national/update/0827/TKY200908270247.html
文部科学省は27日、全国の小学6年生と中学3年生を対象に、今年4月に実施した3回目の全国学力調査の結果を発表した。基礎的な知識を問う問題は答えられるが応用問題には弱い、という傾向は今回もはっきり出ており、改めて課題が浮き彫りに。毎回注目を集める都道府県別の成績は、上位層、下位層とも大きな変化はなかった。
[略]
 調査では携帯電話の利用状況も質問。ほぼ毎日通話やメールをする子は小6で10.0%と前年比1.6ポイント減、中3では31.8%と4.0ポイント減。携帯を持っていない子も、小6は69.1%で1.0ポイント増、中3が39.0%で1.7ポイント増だった。子どもたちの携帯依存やトラブルが問題になり、学校や家庭でルールづくりが進んでいることが背景にあるとみられる。(上野創) 
# http://mainichi.jp/select/wadai/news/20090828k0000m040020000c.html
文部科学省は27日、小6と中3を対象に今年4月に実施した3回目の全国学力・学習状況調査(全国学力テスト)の結果を公表した。都道府県別の平均正答率上位は、3年続けて秋田や福井などほぼ同じ顔ぶれ。下位も中3は順位の固定化が見られたが、小6は大阪などが下位から中位に浮上し、過去2年は小中全科目で最下位だった沖縄が平均との差を縮めるなど、一部で変動も見られた。
[略]
 国公私を合わせた平均正答率はA問題が63〜79%、B問題が51〜75%。昨年より6科目で上昇し、問題量を減らした影響が大きい。中3数学Bで正答率50%未満の学校が18%に達するなど、学校間格差は依然として開いている。経済的に困窮する家庭に学用品の費用などを支給する「就学援助」を受ける児童生徒の割合が高いほど、過去2年と同様に平均正答率が低い傾向が見られた。【加藤隆寛】
# http://sankei.jp.msn.com/life/education/090827/edc0908271712002-n1.htm
文部科学省は27日、小学6年と中学3年を対象に4月に実施した全国学力テスト(学力・学習状況調査)の結果を公表した。都道府県別の正答率では秋田、福井などが引き続き上位となる一方、大阪が小学6年の算数で順位が顕著に上昇するなど、自治体の成績向上への取り組みが反映された。過去2回のテストと合わせて分析した結果、「自分の考えを資料の情報を引用しながら、与えられた条件で書くことが苦手」など、子供たちの課題が明確になった。
[略]
 文科省は結果とともに、課題克服のための「授業アイデア例」を各学校に配布し、テストの一層の活用をうながす。
#

コードの要所を取り上げておきます.一つの文字列の中で,「位」の文字が0回以上何回あるか分からないが,すべてを取り上げるとすると,String#scanを使うのが自然でしょう.その際あわせて,前後の(このコードなら10文字ずつの)文字列も取得するよう,正規表現を書こうなどと欲張ると,「位」の後ろの10文字以内に,「位」があった場合,それが次のパターンマッチの対象にならないという問題があります.irbで,次のようにして確認できます.

$ irb
irb(main):001:0> "abcadeafg".scan(/(.{0,1})(a)(.{0,1})/){|s| puts "#{s[0]}[#{s[1]}]#{s[2]}"}
[a]b
c[a]d
e[a]f
=> "abcadeafg"
irb(main):002:0> "abcadeafg".scan(/(.{0,2})(a)(.{0,2})/){|s| puts "#{s[0]}[#{s[1]}]#{s[2]}"}
[a]bc
[a]de
[a]fg
=> "abcadeafg"
irb(main):003:0> "abcadeafg".scan(/(.{0,3})(a)(.{0,3})/){|s| puts "#{s[0]}[#{s[1]}]#{s[2]}"}
abc[a]dea
=> "abcadeafg"

この問題を回避するため,scanに与えるパターンは「/#{@keyword}/」すなわち「/位/」とし,マッチしてから,$`と$'を用いて,前後の文字列を取り出すことにしました.irbでは,こうです.

irb(main):004:0> "abcadeafg".scan(/a/){|s| puts "#{$`}[a]#{$'}"}
[a]bcadeafg
abc[a]deafg
abcade[a]fg
=> "abcadeafg"

他の工夫として,入力テキストもこのRubyスクリプトに記述しました.Rubyで,URLをもとにサーバにアクセスして,記事コンテンツを取得することのは,決して難しくありませんが,そこからHTMLのタグや,記事本文以外の情報を取り除くという作業に,手間をかけたくなかったので,テキスト直書きとしました.
Rubyの場合,「__END__」だけを書いた行の次から,ファイル末尾までの内容を,「DATA」を使って取得できます.ただしDATAはFileオブジェクトなので,テキストデータが欲しければ「DATA.read」と書かないといけません*1
一つのテキストデータに,読売・朝日・毎日・産経それぞれの記事*2を並べています.そして,分割して記事ごとに処理するため*3,テキストデータに区切り文字を設けています.上のスクリプトでは「#」です.
あと,「split(//)」を使用しているのは,いつものRuby 1.8/1.9対策です.今回のプログラムで,Ruby 1.8で動かすには,「ruby -Ku keyword-detector.rb」とする必要があります.
出力は以下のとおり.

#  http://www.yomiuri.co.jp/national/news/20090827-OYT1T00883.htm
字数(空白除く): 494
学国語Bが昨年の45 位 から34位に上昇した
昨年の45位から34 位 に上昇した。上位グル
34位に上昇した。上 位 グループは中学生の国
に入った。小学生の下 位 グループは沖縄県、北
両科とも3年連続で1 位 となった。福井も3年
は算数Bも昨年の34 位 から27位になったが
昨年の34位から27 位 になったが、中学生は
生は国語・数学とも下 位 グループを抜け出せな
"位"の出現回数: 8
#  http://www.asahi.com/national/update/0827/TKY200908270247.html
字数(空白除く): 881
道府県別の成績は、上 位 層、下位層とも大きな
の成績は、上位層、下 位 層とも大きな変化はな
、福井、富山などが上 位 に来ている。下位層で
が上位に来ている。下 位 層では沖縄、北海道、
目立った。小学校の下 位 で一部変動があるが、
"位"の出現回数: 5
#  http://mainichi.jp/select/wadai/news/20090828k0000m040020000c.html
字数(空白除く): 758
府県別の平均正答率上 位 は、3年続けて秋田や
どほぼ同じ顔ぶれ。下 位 も中3は順位の固定化
ぶれ。下位も中3は順 位 の固定化が見られたが
、小6は大阪などが下 位 から中位に浮上し、過
大阪などが下位から中 位 に浮上し、過去2年は
年は小中全科目で最下 位 だった沖縄が平均との
富山を入れた3県で3 位 までを3年間ほぼ独占
.6ポイント下回る中 位 に。沖縄は小6国語B
国語Bと算数Aで最下 位 を脱し、他4科目で平
「努力した自治体は順 位 が上がっており(地域
"位"の出現回数: 10
#  http://sankei.jp.msn.com/life/education/090827/edc0908271712002-n1.htm
字数(空白除く): 587
福井などが引き続き上 位 となる一方、大阪が小
が小学6年の算数で順 位 が顕著に上昇するなど
"位"の出現回数: 2

こうして見比べると,順位を具体的に書いているのは,読売の記事だけですね.

*1:なぜこんな,リファレンスを読めば分かることを書いたのかというと,「DATA」とだけかいてエラーを起こしてしまったからです.つまり自戒の念をこめてというやつです.

*2:新聞社が複数記事を挙げていたら,どれにしたらいいのかなと,探す前に少し悩みましたが,探してみると,幸いにも各紙,「文部科学省は27日」から始まる記事があり,これを採用しました.

*3:「位」の出現頻度が少ないのは,字数が少ないから,という可能性に対応するため.