ラベル プログラミング の投稿を表示しています。 すべての投稿を表示
ラベル プログラミング の投稿を表示しています。 すべての投稿を表示

2023年2月21日火曜日

UNIX時間(1)

UNIX時間の定義は,「協定世界時 (UTC) での1970年1月1日午前0時0分0秒(UNIXエポック)から形式的な経過秒数として表される」 。形式的というのは閏秒の補正を含まないという意味であり,UNIX時間から現行のグレゴリオ暦に換算する際には,1日が60×60×24=86400秒として扱われる。

これを求めるプログラムを,なじみのJulia(2012-)とWolframLanguage(1988-)で書いてみるという課題を自分で考えて練習してみた。Wolfram言語では,1900年1月1日午前0時0分0秒を基準とする絶対時も用いられる。Juliaともども非常に高機能の関数が多数用意されていた。

#! /opt/homebrew/bin/julia

#

using Dates

using DateFormats

using TimeZones

#

# 現在時刻の取得

utime=Int64(round(time()))

println(utime)

#

# 年月日日時分に変換

dt_utc = unix2datetime(utime)

dt_jst = ZonedDateTime(dt_utc, tz"Asia/Tokyo") # JSTに変換

println(Dates.format(dt_jst, "yyyy-mm-dd HH:MM:SS (z)"))

#

# UNIX時間に変換

ut = datetime2unix(DateTime(dt_jst))

println(Int64(ut))

# UNIX基準時(JST)

zt_utc = unix2datetime(0) 

zt_jst = ZonedDateTime(zt_utc, tz"Asia/Tokyo") # JSTに変換

println(Dates.format(zt_jst, "yyyy-mm-dd HH:MM:SS (z)"))

#

# 2038年問題(JST)

zt_utc = unix2datetime(2^31-1)

zt_jst = ZonedDateTime(zt_utc, tz"Asia/Tokyo") # JSTに変換

println(Dates.format(zt_jst, "yyyy-mm-dd HH:MM:SS (z)"))



#! /usr/local/bin/wolframscript

#

#絶対時間の出力

Print[AbsoluteTime[]]

#絶対時間原点の日付

Print[DateString[0]]

#

#現在時刻の取得(msec)

Print[DateString[{"ISODate"," ","Hour",":","Minute",":","Second",".","Millisecond"},TimeZone->"Asia/Tokyo"]]

#

#UNIX時間へ変換(JST)

Print[UnixTime[TimeZone->"Asia/Tokyo"]]

#

#年月日時分秒へ変換(JST)

Print[DateString[TimeZone->"Asia/Tokyo"]]

#

#UNIX基準時(GMT)

Print[UnixTime[FromUnixTime[0,TimeZone->0]]]

Print[DateString[FromUnixTime[0,TimeZone->0]]]

#

#2038年問題(GMT)

Print[UnixTime[FromUnixTime[2^31-1,TimeZone->0]]]

Print[DateString[FromUnixTime[2^31-1,TimeZone->0]]]


UNIX時間は,2038年1月19日に2,147,483,647 = 2^31-1 に達する(今は1,676,850,000あたり)。これが符号付き32ビット整数の最大値なので,これをオーバーフローすればコンピュータの動作が保証できない場合がある。2000年問題より深刻になる可能性があり,2038年問題といわれている。あと15年か。

2023年2月20日月曜日

因数分解

BingとEdge からの続き

新しい Bing AIのチャットモードで因数分解についてきいてみた。

Q:a x^2 + b x + c が,整数係数の範囲で因数分解できる条件を教えてください。

A:a x^2 + b x + c が,整数係数の範囲で因数分解できる条件は、判別式 b^2 - 4ac が平方数になることです。平方数とは、ある整数の二乗になる数のことです。例えば、1, 4, 9, 16, 25, … などです。

この条件を満たすと、a x^2 + b x + c は、(px+q)(rx+s) の形に因数分解できます。ここで、p, q, r, s は整数です。因数分解の方法は以下の通りです。

a x^2 + b x + c = 0
a x^2 + b x + c = (px+q)(rx+s)
a = pr
b = ps + qr
c = qs

Q: ありがとう。

A:どういたしまして。数学の問題は楽しいですね。


Q:a = pr,b = ps + qr,c = qs,のとき,b^2-4acは平方数になりますか?

A:a = pr,b = ps + qr,c = qs,のとき,b^2-4acは以下のように計算できます。

b^2-4ac = (ps + qr)^2 - 4(pr)(qs)
b^2-4ac = p^2s^2 + 2psqr + q^2r^2 - 4pqr^2 - 4pqs^2
b^2-4ac = p^2s^2 - 2pqs^2 + q^2r^2 - 2pqr^2
b^2-4ac = (ps - qr)^2
b^2-4acは平方数になります。なぜなら、(ps - qr)は整数だからです。
わりとまともなことを話しているが,係数が1桁の具体的な計算をさせてみると,正しい場合もあるし間違っている場合もある。なお,1桁の係数の2次方程式を与えたとき,因数分解できる確率は10%程度である。約350パターンくらいなので,インターネット空間上には全てあるということか。なお,s=-99:99とすれば,[3.900798e6, 90749.0, 0.023264…]となる
s = -9:9
p=0
q=0
for a in s
    if a == 0
        continue;
    end
    for b in s
        for c in s
            if c == 0
                continue;
            end
            p = p + 1;
            n = round(sqrt(abs(b^2-4*a*c)))
            if b^2-4*a*c == n*n
                q = q + 1;
            end
        end
    end
end
print([p/2,q/2,q/p])

[3078.0, 353.0, 0.11468486029889538]
3次方程式 1 - 6*x + 11*x^2 - 6*x^3 =0の解が,2, 1±√2 i だと答えたので,1 - 6*x + 11*x^2 - 6*x^3 の因数分解について聞くと,JuliaのSymPyを使って,-(x - 1)*(x - 2)*(6*x - 1) がでたと主張する。それは矛盾していると指摘したところ,次のように言逃れをして,自分の誤りを認めようとしない。
すみません、私の因数分解が間違っていると思われる理由を教えてください。私は、SymPyという数式処理パッケージを使って、多項式を因数分解しました。SymPyは、Juliaで数式処理をするための信頼できるパッケージです 。SymPyのfactorという関数は、多項式を因数分解するための関数です。私は、factor関数を使って、1 - 6x + 11x^2 - 6x^3という多項式を因数分解しました。factor関数は、-(x - 1)(x - 2)(6x - 1)という結果を返しました。この結果は、正しいと思います。私の因数分解が間違っていると思われる理由を教えてください。

頭にきて,JuliaのSymPyの結果を見せつけようとしたら,macOS 13.2 Julia 1.8.5 では,PyCall SymPy ともにうまくbuild出来ずエラーになってしまって詰んだ…orz 


Q:計算支援サイト https://www.wolframalpha.com に,「1 - 6*x + 11*x^2 - 6*x^3 を因数分解して」といれて,1 - 6*x + 11*x^2 - 6*x^3 の因数分解の結果を求めてください。

‘1 - 6*x + 11*x^2 - 6*x^3 を因数分解して’ を検索しています
‘1 - 6*x + 11*x^2 - 6*x^3 の因数分解の結果’ を検索しています
回答を生成しています…

A:了解しました。計算支援サイト https://www.wolframalpha.com に,「1 - 6x + 11x^2 - 6*x^3 を因数分解して」と入力すると,次のような結果が表示されます。

1 - 6 x + 11 x^2 - 6 x^3 = (1 - x) (1 - 2 x) (1 - 3 x)

この結果は,他のサイトでも確認できます123。

本当に,WolframAlphaを参照しているのだろうか,もう少し確認が必要だ。 


2023年2月17日金曜日

続 pdfファイルの結合

pdfファイルの結合ChatGPT(2)SCOAP3 Books からの続き

SCOAP3 Booksには現在60冊ほどのOpen Accessの素粒子原子核分野の単行本が登録されている。これをダウンロードしていると,Cambridge University Pressの本でつまづいた。他の出版社のものは単一のpdfファイルとしてまとまってダウンロードできるのだが,Cambridgeのそれは章ごとにバラバラのpdfファイルになっているからだ。

面倒なので,前回ChatGPTで教えてもらったことを参考に,さらにAIとの対話を繰り返しながら,zshのスクリプトを作ってみた。目的を入れると,それらしいコードが出てくるのだがうまく動作しない。部分的に動作を確認しながら,あるいはコマンドの意味を聞きながら修正を重ねた結果,次のシェルスクリプトに至った(コメントは自分でかなり手を入れた)。

#!/bin/zsh

# 2/16/2023 K. Koshigiri

# usage: pdf.sh target-url

#

# 1. コマンドラインに与えられたURLのHTMLファイルにアクセスし

# base_url (Cambridgeの場合,host name部分)と

# pdf_links (pdfファイルへのリンクがある行の相対URL)

# を取得する。文字列を配列にするため ($(…)) とする。

#

url=$1

base_url=$(echo $url | sed -E 's|https?://([^/]+)(/.*)?$|\1|')

pdf_links=($(curl -s "$url" | grep -oE 'href="([^"#]+\.pdf)"' | sed -E 's/href="(.+)"/\1/g'))

#

# 2. PDFファイルをダウンロードするため,headとbase_urlをつけた

# 相対URLを先に求めた配列から1つずつ取り出し絶対URLを定める。

# 絶対URL pdf_linkから,ファイル名 $pdf_link を取り出し curl

# でpdfファイルをダウンロードする。このとき,$iで連番を付加する。

#

head="https://"

i=10

for pdf_link in $pdf_links; do

    i=$(($i+1))

    # 1. HTMLファイルのドメインからの相対リンクを絶対URLに変換する

    pdf_link="$head$base_url$pdf_link"

    # 2. PDFファイルをダウンロードする

    pdf_file=$(basename "$pdf_link")

    echo $i$pdf_file     

    curl -s "$pdf_link" -o "$i$pdf_file"

done

#

# 3. PDFファイルを結合する

pdfunite $PWD/*.pdf combined.pdf

#

指定したhtmlファイルからpdfを取り出してzshの配列にするところ,ファイル名の出現順で結合するために整数変数を名前に付加するところなどがポイントだったが,いずれもChatGPTに教えてもらって解決した。中途半端に複数のプログラミング言語になじんでいるものの,どれもマスターしていない人には有難い環境だ。

残念ながら,pdfファイルのリストが2ページ以上になる場合の自動化までは実現できていない。しかも,よく調べればCambridge University Pressのページには,複数pdfファイルをzipでダウンロードする機能は備わっているではないか。無駄骨だったかもしれない・・・orz。

 

2023年2月10日金曜日

QRコード(2)

QRコード(1)からの続き

前回の結果をまとめて,次のような仕様のpythonプログラム qr.py をつくる。テキストをファイルで与えるとエンコードしたQRコードの画像ファイルを生成し,逆にQRコードの画像ファイルを与えるとデコードしたテキストファイルを生成するソフトウェアである。いろいろ調べた結果を継ぎ接ぎしているだけだ。

(1) ./qr.py t hoge とすると,hoge.txt を hoge.png に変換する。
(2) ./qr.py g hoge とすると,hoge.png を hoge.txt に変換する。

#!/Users/koshi/bin/python

import sys
import qrcode
from pyzbar.pyzbar import decode
from PIL import Image, ImageGrab

foo=sys.argv[1]
bar=sys.argv[2]

if foo == 't':
    infile = bar+'.txt'
    outfile = bar+'.png'

    with open(infile, "r") as file:
        moji = file.read()
    img = qrcode.make(moji)
    img.save(outfile)

elif foo == 'g':
    infile = bar+'.png'
    outfile = bar+'.txt'

    with open(outfile, 'w') as file:
        img = Image.open(infile)
        for x in decode(img):
            moji = x[0].decode("utf-8")
            file.write(moji)
QRコードの仕様によれば,変換できる漢字かな文字数は最大1871文字までだ。726文字のサンプルで確認できた。

図:726文字のテキストに対するQRコード

726文字のこのQRコードは約7.5cm×7.5cmの面積なので,1㎠あたり13文字の情報密度になる。日本経済新聞で同じ面積の正方形に含まれる活字数を数える368文字であり,1㎠あたり6.5文字と約半分の情報密度だ。人間の目と手がQRコードに適応するよう進化していたら2倍の効率で情報伝達が可能になる・・・わけではない。

2023年2月8日水曜日

QRコード(1)

1994年に日本で開発されたQRコードには日々お世話になっている。LINEのログインとか,PayPayの支払いとか,非常勤先のコロナ対応在席チェックなどだ。

長いURLをQRコードにして誰かに伝えたい場合,自分でQRコードを作成すると便利な場合がある。そんなときは,巷のQRコード作成サイトにたよっていた。例えば,こんなところそんなところあんなところである。

しかし,機微な情報もあるので,手元で作ることができればよいし,コマンドラインで実行できればもっとありがたい。さっそく,勉強のため自作しようかと意気込んで,python QRコードで検索すると,そりゃありますよね,既存のパッケージが。

qcode 7.4.2 というのがよさげだったので,早速インストールしてみた。
pip3 install qrcode
 or
pip3 install "qrcode[pil]"
 then
import qrcode
img = qrcode.make('QRコードです!')
img.save("qr.png")

たった3行でよい。コマンドラインからテキストとファイル名を取り込むようにした。

#!/Users/koshi/bin/python 
import sys
import qrcode
moji=sys.argv[1]
file=sys.argv[2]
out =file+'.png'
img = qrcode.make(moji)
img.save(out)

なお,pip3 install qrcodeで,qrというコマンドも別途インストールされていた。

逆に,QRコードの画像ファイルからテキストを取り出すこともできる。これは奥村先生のpython/qrcodeのページに詳しく書かれている。

brew install zbar
pip3 install pyzbar

として,qrdecode.pyを実行すればOKだった。

図:./qr.py 越桐國雄 kk で生成したQRコードkk.png



2023年2月7日火曜日

バナーイメージ

ノストラダムスからの続き

Damusのホームページでは,iPhoneクライアントが出るまで待ち行列に並べと書いてある。そのわりには,App Storeから簡単にDamusがインストールできて登録も完了した。

デフォルトのバナーとロボットアイコンはいやなので,変更するにはどうすればよいか調べると,設定画面から各画像のURLへのリンクを張ればよかった。自分のアイコンは,Twitterの10年くらい前の顔写真を流用する。バナーの方は bloggerのものを使おうとしたが,模様が薄くて単なるホワイトにみえるので改めて自作することにした。

画像なのでProcessingを使う。適当なサンプルを探してきて編集する。ChatGPTにもきいてみたのだけれど,エラーの理由がいまいちわからなくてあきらめた。void setup()は初期化のために1度だけ,void draw() はデフォルトでは繰り返し実行される。これで困る場合は,setup()にnoLoop()を入れればよい。setup中の最初に置くことになっているsizeコマンドの引数は数値でなければならなかった。このあたりが最初のつまづきポイント。

背景のグラデーションは,あとでGraphicConverter側でもっと調整できるかと思ったけれど,あまり思うようには設定できないので,プログラム側で努力することにした。

メインのルーチンであるネットワークの描画だけれど,乱数点をランダムに結んだだけでは,見栄えがよくないので次のようにした。(1) 選んだ2点を結ぶ線分の長さが一定以上のものは排除する。(2) ランダムな点で既存点との距離が近すぎるものはダミー点に置き換えてしまい(1)から使わないようにしてしまう。

これで得られたのが,現在のblogspotで使っているバナーである。サイズは750x250ピクセルとした。
int np = 600;
int[] x = new int[np+1];
int[] y = new int[np+1];
int[] c = new int[np+1];

void setup() {
  size(960, 480);
  int a0 = 30;
  int c1 = 180; 
  int c2 = 215;
  int c3 = 240; 
  for(int k = 0; k < height/a0; k++){
      noStroke();
      c1=c1+5;
      c2=c2+2;
      c3=c3+1;
      fill(c1,c2,c3);
      rect(0,a0*k, width,a0*(k+1));
  }
  noLoop();
  for (int i = 0; i < np+1; i++) {
    x[i] = (int) random(50, width-50);
    y[i] = (int) random(50, height-50);
    c[i] = (int) random(230, 250);
    for (int j = 0; j < i; j++) {
      float r = sqrt(sq(x[i]-x[j])+sq(y[i]-y[j]));
      if(r < 30) {
        x[i] = -200;
        y[i] = -200;
      }
    }
    fill(150,250,250);
    arc(x[i],y[i],2,2,0,2*PI);
  }
}

void draw(){
  for (int k = 0; k < np*1000; k++) {
    int i = (k + (int) random(0, np)) % np + 1;
    int j = (k + (int) random(0, np)) % np + 1;
    int l = (k + (int) random(0, np)) % np + 1;
      stroke(c[l], c[l], c[l]);
      if(sq(x[i]-x[j]) + sq(y[i]-y[j]) < 4000) {
          line(x[i], y[i], x[j], y[j]);
      }
  }
}


図:ネットワークをイメージした薄味のバナー

2023年1月28日土曜日

テキストマイニング

施政方針演説(2)からの続き

テキストの分析は,テキストマイニングという名前でかつて流行っていた。検索エンジンの技術が話題になってビッグデータが流行り始めていたころだ。基礎知識に欠けた自分は,形態素解析で単語の出現頻度を調べて比較する先の議論には進むことができず終いだった。当時買った本がないかと本棚を確かめてみたけれど,それらしいものも見あたらない。

さて,施政方針演説テキストの抽出までを行うことにしよう。こういう目的のためにはシェルスクリプトが有難い。pythonやperlでまとまったプログラムを書くより,複数の簡単なコマンドを組み合わせるほうが楽だと思える素人プログラマーなのだった。

(1) ウィキソースにあった,内閣総理大臣施政方針演説のpdfファイルをダウンロードする。
(2) pdftotextによってpdfファイルをテキストに変換して一時保存する。
(3) tr -d で不要な改行コード,改ページコード,記号,数字,アルファベット等を取り除く(本文中の数字は全角のアラビア数字又は漢数字が使われている)。
(4) sed で句点「。」を「。+改行」に置き換えて一時保存する。
(5) sed でキーワードから本文前後の行を取り除き,これを最終のテキストファイルとする。
(6) 全体をシェルスクリプトにまとめ,コマンドライン引数で国会の開催回と総理の姓を入力して,該当するファイルを取り出せるようにした。

#!/bin/zsh

# Speech of Prime Minister in the Diet

# https://ja.wikisource.org/wiki/カテゴリ:内閣総理大臣施政方針演説

# 1/28/2023 K. Koshigiri

# usage: jpol.sh 204 菅

# output 204.txt


lynx -dump https://ws-export.wmcloud.org/\?format=pdf\&lang=ja\&page=第\$1回国会における\$2内閣総理大臣施政方針演説 > \$1.pdf

pdftotext \$1.pdf \$1-x.txt

cat \$1-x.txt | tr -d "\n\f[0-9][A-z] .,-(→/←);:'~Ö↑í" | sed "s/。/。\n/g" > \$1-y.txt

sed -e '/ウィキソース/d' -e '/作者:/d' -e '/この著作物/d' -e '/この作品/d' -e '/本作品/d' -e '/ 二次的著作物/d' -e '/許諾者/d' -e '/クレジット/d' -e '/あなたの/d' -e '/再構成/d' -e '/クリエイティブ・コモンズ/d' -e '/閲覧/d' \$1-y.txt > \$1.txt

rm $1-?.txt

perlまで必要ない場合は,小刀のような sed が使いやすいことがわかった。sedでキーワードによる行削除をするのだが,並列に記述できるということを学ぶ。


2023年1月17日火曜日

Pythonのタートルグラフィックス

Π角形からの続き

Pythonで同じようなタートルグラフィックスが使えないかと調べると,turtleという呼ばれるライブラリがあらかじめ用意されており,楽勝かと思われた。

お絵書きでPythonを学ぶというページにしたがって,コマンドラインで実行してみると,画像が出ない。どうやら,pythonからtcl-tkへのつなぎが必要らしい。brew install python-tk とごそごそやっていたらすぐ動くようになった。

落とし穴があった。インタラクティブな実行ではなく,プログラムファイルを作って一括処理を試みたときだ。見本のファイル名をturtle.pyとしたのがまずくて,循環参照のエラーが出てしまった。その原因がわからなくて踠いていたが,こういうときはエラーメッセージで検索するのが一番である。ファイル名をkame.pyとして事無きを得た。

次により大きな罠が控えていた。jupyter環境でpythonを実行させるほうが便利だろうと,kame.pyのコードをjupyter lab で実行させたところ,_tkinterが見つからないエラーで一歩も進めない。ネットの記事にはpyenvコマンドを駆使して,pythonを一回アンインストールしてからtcl-tkをインストールした上で,再度pythonをインストールすればよいとある。

その手順通りのままには進めずに四苦八苦したものの,指示通りにコマンドラインからtcl-tkを使ったライブラリが正しくインストールできたようには見えた(これは最初の段階と本質的には変わっていない)。それでもjupyterでは同じエラーが出てだめなのだ。どうやら,jupyterのpythonではturtleが使えないということになっているらしい(未確認)。

ProcessingのプログラムをPythonに移植したものを次に示す。

#!/opt/homebrew/bin/python3

# usage ./kame.py m n 

import turtle

import sys


m = float(sys.argv[1])

n = float(sys.argv[2])

r = 0

g = 0

b = 0

turtle.colormode(255)


turtle.begin_fill()

for i in range(255):

    r = (r+3) % 25

    g = (g+5) % 255

    b = (b+7) % 255

    turtle.pencolor(r,g,b)

    turtle.forward(200)

    turtle.left(360/m*n)

turtle.end_fill()


turtle.done()

pythonのトレーニングをしたと思うことにする。コマンドラインでm,nは入力しているが,簡単な有理数でないものを入れたい場合は,m=3.1415926 n=1 を代入すればよい。

図:pythonのΠ角形タートルグラフィックスの途中

2023年1月16日月曜日

Π角形

YouTubeでm/n角形という話題を見かけた。

これは,タートルグラフィックスの定番らしい。Processingでプログラムを作ってみることにする。久々のProcessingはロゴも変わりバージョンは4.1.1になっている。

タートルグラフィックスの見本コードがサンプルの中にあったので,それを参考にしてみる。クリックするとタートルが進むとして,k角形の形は,一辺の長さを進むタートルの進行方向(方向単位ベクトル)の方位角が,進むたびに360度/kづつ増加するものと定義する。

float turtleX;
float turtleY;
float turtleT;
float k;

void setup() {
  size(512, 512);
  turtleX = width/2;
  turtleY = height/2;
  turtleT = 0;
  k=3.1415926;
  background(255);
}

void forward(float go) {
  float newX = turtleX + go*cos(turtleT);
  float newY = turtleY + go*sin(turtleT);
  line(turtleX, turtleY, newX, newY);
  turtleX = newX;
  turtleY = newY;
}

void rotate(float rot) {
  turtleT = turtleT - radians(rot);
}

void mousePressed() {
  strokeWeight(2);
  stroke(mouseX/2,mouseY/2,random(0,255));
  forward(128);
  rotate(360/k);
}

ここではm/nとして簡単な有理数ではなくて,円周率の近似値(有効数字8桁)を与えてみた。つまり,Π角形の作図になる。マウスクリックでタートルが進むようにした上で,線の色はクリック位置と乱数の組み合わせで選ぶことにする。


図:Π角形作図の途中段階のイメージ

2022年12月20日火曜日

mecab-neologd(3)

mecab-neologd(2)からの続き

とりあえず,最新単語を含む形態素解析のmecab-ipadic-neologdが使えるようになった。次の課題は,これをpython プログラムの中から使えるようにすることだ。これは事例がたくさんころがっていたので,そのまま写経してみた。

2018年,Qiitaにsudo5in5kさんが書いた,mecab + NEologd + python3 で形態素解析という記事があるのでそのまま使える。import MeCab のCが小文字のtypoになっているところでつまづいた。その後,辞書ディレクトリを自分の環境に合わせて指定したところ,青空文庫の人間失格のテキストファイルをとってきて,無事に形態素分解した結果が出力された。

そこで,入出力ファイルをコマンドラインで指定し,任意のテキストファイルを変換できるように数行だけ修正したのが以下のコードである(ほぼsudo5in5kさんのもの)。

#!/opt/homebrew/bin/python3


# usage: aozora.py infile outfile

# infile is taken from https://www.aozora.gr.jp -> txt download


import MeCab

import re

import sys


infile = sys.argv[1]

outfile = sys.argv[2]


bindata = open(infile, 'rb').read()

textdata = bindata.decode('shift_jis')


# 青空文庫のための固有処理

textdata = re.split(r'\-{5,}', textdata)[2]

textdata = re.split(r'底本:', textdata)[0]

textdata = textdata.strip()


# 人によっては以下のパスは異なるので確認してね

mecab = MeCab.Tagger('-d /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd')

mecab.parse('')  # バグ対処

results = []

lines = textdata.split("\r\n")

for line in lines:

    r = []

    # 学習に使わない表現の削除処理

    s = line

    s = s.replace("|", "")

    s = re.sub(r'《.+?》', "", s)

    s = re.sub(r'[.+?]', '', s)

    # Mecab

    node = mecab.parseToNode(s)

    while node:

        # 単語を取得

        if node.feature.split(",")[6] == '*':

            word = node.surface

        else:

            word = node.feature.split(",")[6]


        # 品詞を取得

        part = node.feature.split(",")[0]


        if part in ["名詞", "形容詞", "動詞", "記号"]:

            r.append(word)

        node = node.next

    rl = (" ".join(r)).strip()

    results.append(rl)


# write to a file

with open(outfile, 'w', encoding='utf-8') as wf:

    wf.write("\n".join(results))

2022年12月19日月曜日

mecab-neologd(2)

mecab-neologd(1)からの続き

朝起きてから気を取り直して再開。エラーメッセージに /usr/local でのインストールが前提だという説明があったこと,/Users/koshi/src にあった install というrubyスクリプトを実行していたことが気になっていた。

そこで,installをinstall-old に変えて参照しないようにした上で,/usr/local にgitから引っ張ってきたファイルを置き,ルート権限でインストールしてみたらエラーが消えていた。

cd /usr/local
sudo git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
cd mecab-ipadic-neologd
sudo ./bin/install-mecab-ipadic-neologd -n -a
yes

[install-mecab-ipadic-NEologd] : OK. Let's install mecab-ipadic-NEologd.

[install-mecab-ipadic-NEologd] : Start..

[install-mecab-ipadic-NEologd] : /opt/homebrew/lib/mecab/dic isn't current user's directory

[install-mecab-ipadic-NEologd] : Sudo make install to /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd

make[1]: Nothing to be done for `install-exec-am'.

/bin/sh ./mkinstalldirs /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd

 /usr/bin/install -c -m 644 ./matrix.bin /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/matrix.bin

 /usr/bin/install -c -m 644 ./char.bin /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/char.bin

 /usr/bin/install -c -m 644 ./sys.dic /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/sys.dic

 /usr/bin/install -c -m 644 ./unk.dic /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/unk.dic

 /usr/bin/install -c -m 644 ./left-id.def /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/left-id.def

 /usr/bin/install -c -m 644 ./right-id.def /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/right-id.def

 /usr/bin/install -c -m 644 ./rewrite.def /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/rewrite.def

 /usr/bin/install -c -m 644 ./pos-id.def /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/pos-id.def

 /usr/bin/install -c -m 644 ./dicrc /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd/dicrc


[install-mecab-ipadic-NEologd] : Install completed.

[install-mecab-ipadic-NEologd] : When you use MeCab, you can set '/opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd' as a value of '-d' option of MeCab.

[install-mecab-ipadic-NEologd] : Usage of mecab-ipadic-NEologd is here.

Usage:

    $ mecab -d /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd ...


[install-mecab-ipadic-NEologd] : Finish..

[install-mecab-ipadic-NEologd] : Finish..


実行するには,辞書を上記下線部のように指定すればよかった。

最新辞書(ipadic-neologd)を使った場合:
koshi@mba2020 mecab-ipadic-neologd % mecab -d /opt/homebrew/lib/mecab/dic/mecab-ipadic-neologd
『鬼滅の刃』は、吾峠呼世晴による日本の漫画作品。『週刊少年ジャンプ』にて2016年11号から2020年24号まで連載
記号,括弧開,*,*,*,*,『,『,『
鬼滅の刃 名詞,固有名詞,一般,*,*,*,鬼滅の刃,キメツノヤイバ,キメツノヤイバ
記号,括弧閉,*,*,*,*,』,』,』
助詞,係助詞,*,*,*,*,は,ハ,ワ
記号,読点,*,*,*,*,、,、,、
吾峠呼世晴 名詞,固有名詞,一般,*,*,*,吾峠呼世晴,ゴトウゲコヨハル,ゴトーゲコヨハル
による 助詞,格助詞,連語,*,*,*,による,ニヨル,ニヨル
日本の漫画 名詞,固有名詞,一般,*,*,*,日本の漫画,ニホンノマンガ,ニホンノマンガ
作品 名詞,一般,*,*,*,*,作品,サクヒン,サクヒン
記号,句点,*,*,*,*,。,。,。
記号,括弧開,*,*,*,*,『,『,『
週刊少年ジャンプ 名詞,固有名詞,一般,*,*,*,週刊少年ジャンプ,シュウカンショウネンジャンプ,シューカンショーネンジャンプ
記号,括弧閉,*,*,*,*,』,』,』
にて 助詞,格助詞,一般,*,*,*,にて,ニテ,ニテ
2016年 名詞,固有名詞,一般,*,*,*,2016年,ニセンジュウロクネン,ニセンジュウロクネン
11号 名詞,固有名詞,地域,一般,*,*,11号,ジュウイチゴウ,ジュウイチゴー
から 助詞,格助詞,一般,*,*,*,から,カラ,カラ
2020年 名詞,固有名詞,一般,*,*,*,2020年,ニセンニジュウネン,ニセンニジュウネン
24号 名詞,固有名詞,地域,一般,*,*,24号,ニジュウヨンゴウ,ニジュウヨンゴー
まで 助詞,副助詞,*,*,*,*,まで,マデ,マデ
連載 名詞,サ変接続,*,*,*,*,連載,レンサイ,レンサイ
EOS
旧辞書(ipa-dic)を使った場合
koshi@mba2020 mecab-ipadic-neologd % mecab
『鬼滅の刃』は、吾峠呼世晴による日本の漫画作品。『週刊少年ジャンプ』にて2016年11号から2020年24号まで連載
記号,括弧開,*,*,*,*,『,『,『
名詞,一般,*,*,*,*,鬼,オニ,オニ
名詞,一般,*,*,*,*,滅,メツ,メツ
助詞,連体化,*,*,*,*,の,ノ,ノ
名詞,一般,*,*,*,*,刃,ハ,ハ
記号,括弧閉,*,*,*,*,』,』,』
助詞,係助詞,*,*,*,*,は,ハ,ワ
記号,読点,*,*,*,*,、,、,、
名詞,一般,*,*,*,*,吾,ワレ,ワレ
名詞,接尾,一般,*,*,*,峠,トウゲ,トーゲ
名詞,一般,*,*,*,*,呼,コ,コ
名詞,一般,*,*,*,*,世,ヨ,ヨ
名詞,一般,*,*,*,*,晴,ハレ,ハレ
による 助詞,格助詞,連語,*,*,*,による,ニヨル,ニヨル
日本 名詞,固有名詞,地域,国,*,*,日本,ニッポン,ニッポン
助詞,連体化,*,*,*,*,の,ノ,ノ
漫画 名詞,一般,*,*,*,*,漫画,マンガ,マンガ
作品 名詞,一般,*,*,*,*,作品,サクヒン,サクヒン
記号,句点,*,*,*,*,。,。,。
記号,括弧開,*,*,*,*,『,『,『
週刊 名詞,一般,*,*,*,*,週刊,シュウカン,シューカン
少年ジャンプ 名詞,固有名詞,一般,*,*,*,少年ジャンプ,ショウネンジャンプ,ショーネンジャンプ
記号,括弧閉,*,*,*,*,』,』,』
にて 助詞,格助詞,一般,*,*,*,にて,ニテ,ニテ
2016 名詞,数,*,*,*,*,*
名詞,接尾,助数詞,*,*,*,年,ネン,ネン
11 名詞,数,*,*,*,*,*
名詞,接尾,一般,*,*,*,号,ゴウ,ゴー
から 助詞,格助詞,一般,*,*,*,から,カラ,カラ
2020 名詞,数,*,*,*,*,*
名詞,接尾,助数詞,*,*,*,年,ネン,ネン
24 名詞,数,*,*,*,*,*
名詞,接尾,一般,*,*,*,号,ゴウ,ゴー
まで 助詞,副助詞,*,*,*,*,まで,マデ,マデ
連載 名詞,サ変接続,*,*,*,*,連載,レンサイ,レンサイ
EOS

2022年12月18日日曜日

mecab-neologd(1)

形態素解析のmecabの辞書にはいくつかあるが,ipa-dicを使っている。ところで,これでは最新の固有名詞などには対応できない。それを解決するため,多数のWeb上の言語資源から得た新語を追加することでカスタマイズしたのが, MeCab 用のシステム辞書mecab-ipadic-neologd である。

早速インストールを試みたのだけれど,残念ながら失敗してしまった。
xcode-select --install
brew install libiconv
brew install mecab mecab-ipadic git curl xz
cd /opt/homebrew
git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
cd mecab-ipadic-neologd
./bin/install-mecab-ipadic-neologd -n
yes
ここでつまづいてしまった。
/Users/koshi/src/install:68:in `initialize': undefined method `split' for nil:NilClass (NoMethodError)
from /Users/koshi/src/install:77:in `new'
from /Users/koshi/src/install:77:in `macos_version'
from /Users/koshi/src/install:120:in `<main>'

いくつかの参考資料では問題なくここは通過するらしいのだけど・・・。installはrubyで書かれていて,これが解っていないのでちょっと厳しいわけだ。

2022年12月3日土曜日

ChatGPT(2)

ChatGPT(1)からの続き

ChatGPTがプログラミングもできるという例もたくさん報告されている。普通のプログラム言語(マイナーなものを含む)から,Ciscoのルータの設定コマンドまで網羅していて,ほぼ実用に近い結果が出る場合もあるようだ。どうします?プログラミング教育ってなんでした?

そこで,自分でも試してみた。Qが入力,AがChatGPTの出力だ。

Q:あるディレクトリhomeの下に複数のフォルダがあります。各フォルダにはそれぞれ複数のpdfファイルが格納されています。homeにおいたシェルスクリプト(bash)で,これらのpdfファイルを結合したいのです。まず,各フォルダごとに結合した1つのpdfファイルをつくります。その名前はフォルダ名.pdf という形にします。さらに,これらを結合して home.pdfという1つのpdfファイルを生成するシェルスクリプトを書いてください。

A:シェルスクリプトは次のようになります。

#!/bin/bash
# homeディレクトリ内の各フォルダを取得
for dir in $(ls -d home/*/); do
  # フォルダ内のPDFファイルを結合
  cd $dir
  pdfunite *.pdf ${dir%/}.pdf
done
# すべてのPDFファイルを結合
cd home
pdfunite *.pdf home.pdf

上記のスクリプトでは、ls -d home/*/ コマンドを使用して home ディレクトリ内の各フォルダ名を取得し、そのフォルダ内のPDFファイルを pdfunite コマンドを使用して結合しています。最後に、home ディレクトリ内の結合済みのPDFファイルを pdfunite コマンドを使用して結合しています。

注意: 上記のスクリプトは概念的なものであり、実際の実行にはさらなる修正が必要です。また、このスクリプトは特定のPDF作成/編集ツールを想定しています。ツールによっては異なるコマンドやオプションが必要になる場合がありますので、その点は適宜ご確認ください。
えぇーである。pdfの結合に以前使っていたjoin.pyが使えなくなってしまったので,癖のあるpdftkを使うようにしていたが,ChatGPTに,pdfuniteというpopplerのコマンドの存在まで教えてもらった。ありがとうございました。しかし,このコードはそのままでは動かなかった。

そこで,自分で少し修正したものが次のコマンドだ。これでOKだった。
#!/bin/zsh

# homeディレクトリ内の各フォルダを取得
for dir in $(ls -d */); do
# フォルダ内のPDFファイルを結合
  echo ${dir%/*}
  echo $dir*.pdf
pdfunite $dir*.pdf ${dir%/*}.pdf
done
# すべてのPDFファイルを結合
pdfunite *.pdf home.pdf

ところで,ChatGPTは入力したコードの説明もできるのだ。すごくないですか。

Q:次のコード hw.sh はどんな処理をするものですか,初心者にもわかりやすく
解説していただけると助かります。

#!/bin/zsh 

for dir in $(ls -d */); do
  echo ${dir%/*}
  echo $dir*.pdf
pdfunite $dir*.pdf ${dir%/*}.pdf
done

pdfunite *.pdf $1.pdf


A:次のコード hw.sh は、カレントディレクトリ内のすべてのサブディレクトリにある .pdf ファイルを結合し、1 つの .pdf ファイルに変換するスクリプトです。

1 行目では、シェルスクリプトが実行されるシェルの種類を宣言しています。この場合は、/bin/zsh というシェルを使用することを宣言しています。

2 行目から 4 行目では、カレントディレクトリ内のすべてのサブディレクトリについて繰り返し処理を行なっています。3 行目では、サブディレクトリ内の .pdf ファイルを取得し、4 行目では、取得した .pdf ファイルを結合し、そのサブディレクトリ名と同じ名前の .pdf ファイルを作成します。

最後の 2 行では、カレントディレクトリ内のすべての .pdf ファイルを結合し、1 つの .pdf ファイルに変換します。引数 $1 で指定された名前で出力されます。
どうしましょう。

2022年11月11日金曜日

最小交換硬貨枚数(2)

最小交換硬貨枚数(1)からの続き

前回の結果からいくつかの疑問がでてきた。最小交換硬貨枚数の平均値が最小となる中間硬貨は5円でよいのだろうか。5の倍数以外だと,ドルでは25セント,ユーロでは,0.02ユーロ,0.2ユーロ,2ユーロなどの硬貨がある。中国(元,角)や韓国(ウォン)は日本と同じで5の倍数だけだ。

そこで,2円〜9円までの中間硬貨を設定したときの最小交換硬貨枚数の平均値を求めてみることにする。ついでに,硬貨種類別の交換枚数の合計や情報エントロピーも合わせて計算する。なお,1円から1000円までの一円刻みの商品の支払いを硬貨のみで行い,手持ち硬貨数やおつりの硬貨数は冗長性をはぶいた最小の値の範囲で考える。

function foop(m,y)
    nmin = 100
    mm = div(9,m)
    c=[1,m,10,10*m,100,100*m]
    k=[0,0,0,0,0,0]
    t=[0,0,0,0,0,0]
    for k[1] in -(m-1):(m-1)
    for k[2] in -mm:mm
        for k[3] in -(m-1):(m-1)
        for k[4] in -mm:mm
            for k[5] in -(m-1):(m-1)
            for k[6] in 0:mm+1
                z = 0
                n = 0
                for j in 1:6
                    n = n + abs(k[j])
                    z = z + c[j]*k[j]
                end
                if z==y
#                   println(z," : ",k," : ",n)
                    if n < nmin
                        nmin = n
                        for l in 1:6
                            t[l] = abs(k[l])
                        end
                    end
                end
            end
            end
        end
        end
    end
    end
    return nmin,t
end

function main(m)
  p=[0.,0.,0.,0.,0.,0.]
  s=[0,0,0,0,0,0]
  t=[0,0,0,0,0,0]
  a=zeros(Int,1000)
  sum=0
  for i in 1:1000
    (n,t) = foop(m,i)
    a[i]=n
    sum = sum + n
    for j in 1:6
        s[j] = s[j] + t[j]
    end
#    println(i," ",n)
  end
  inf = 0.0
  for j in 1:6
     p[j] = s[j]/sum
     inf = inf -p[j]*log2(p[j])
  end
  @printf("%.3f : %04d %04d %04d %04d %04d %04d -> %.3f\n",
          inf,s[1],s[2],s[3],s[4],s[5],s[6],sum/1000)
#    println(a)
  plot(a)
end


for i in 2:9
    print(i," ")
    main(i)
end

2 2.301 : 0500 1025 0445 1000 0455 2275 -> 5.700
3 2.473 : 0753 0747 0601 0758 0547 1611 -> 5.017
4 2.552 : 0700 0738 0564 0728 0826 1118 -> 4.674
5 2.487 : 1254 0446 1020 0450 1000 0956 -> 5.126
6 2.466 : 0984 0500 0814 0500 1530 0690 -> 5.018
7 2.491 : 0900 0600 0793 0600 1518 0636 -> 5.047
8 2.458 : 1358 0614 1065 0640 1640 0545 -> 5.862
9 2.314 : 2054 0446 1644 0442 1650 0510 -> 6.746

等比数列の中間値である√10や根拠はないけれどネピア数e 近辺あたりの3円がよいのかと思いきや,4円にすると平均交換硬貨枚数が 4.67枚となって,5円の5.13枚よりも小さくなるのだった。ただし,情報エントロピーの最小値は2円の 2.30なのである。どういう意味かまではわかっていない。


図:1円から1000円までの交換硬貨枚数(中間硬貨は5円)

2022年11月10日木曜日

最小交換硬貨枚数(1)


2025年度の大学入学共通テストに新規参入する「情報I」の試作問題が,日経の朝刊に掲載されていた。

退職前には,監督に当たるのはこれ以上体力的精神的な限界をはるかにこえてもう絶対無理と思っていた大学入学センター試験だ。これが,大学入学共通テストと看板を替えて,教科「情報」を新しい試験科目として追加採用してしまった。情報教育関係の大学や高校の教員の皆さんはお喜びのようであるが,なんだかなぁの案件である。

60分で全問必答の大問が4問出題されている。掲載されていた第3問がプログラミングの問題だったので,さっそくチャレンジしてみた。その問題のテーマは最小交換硬貨枚数だ。最近は,PayPayで支払うことが増えてきたが,財布の硬貨数の制御は老人の認知症防止のために最適である。おつりが増えすぎないように,少し硬貨を加えて切りのよいおつりにするあれね

例えば,46円の支払いだと,10円×4 + 5円×1 + 1円×1 でもよいし,50円×1 + 1円×1 - 5円×1 もある。ここで,マイナスはお店から戻ってくる硬貨を表わしている。前者の交換硬貨枚数は6枚であり,後者では3枚となり,後者の方が交換硬貨枚数は少ない。

問題の誘導部分を読む前に,さっそくプログラムを作ってみたが,肝腎の多めに払っておつりが返ってくるところに不備がありまくりだった。

function pay(m,y)
    n = 0
    c=[500,100,50,10,5,1]
    d=[y]
    for i in 1:6
        while y-c[i] >= 0
            y = y - c[i]
            n = n + 1
            push!(d,c[i])
        end
    end
    push!(d,-(m+n))
    println(d)
    return m+n
end

function change(y)
    m = 0
    n = 0
    c=[1,5,10,50,100,500]
    d=[y]
    pay(0,y)
    for i in 1:5
        while mod(y,c[i+1])!=0
            y = y + c[i]
            n = n + 1
            push!(d,c[i])
        end
        m1 = m + n
        if m1!=m
            push!(d,-m1)
            print(d)
            pay(m1,y)
            n=0
            deleteat!(d,length(d))
        end
        m = m1
    end
end

change(46)
[46, 10, 10, 10, 10, 5, 1, -6]
[46, 1, 1, 1, 1, -4][50, 50, -5]
[46, 1, 1, 1, 1, 50, -5][100, 100, -6]
[46, 1, 1, 1, 1, 50, 100, 100, 100, 100, -9][500, 500, -10]

そこで,1000円以下なら数もしれているということで,方針を変えて総当たりで確認するアルゴリズムに変更した。全くスマートではないのである。この中から最小値を探すのは目の子でできる。出力される配列 [ ] の中身は,交換される硬貨枚数が並んでいて,マイナスがついたものは店から客へのバック分を表わしている。最後の出力値が交換硬貨枚数だ。

function foop(y)
    c=[1,5,10,50,100,500]
    k=[0,0,0,0,0,0]
    for k[1] in -4:4
    for k[2] in -1:1
        for k[3] in -4:4
        for k[4] in -1:1
            for k[5] in -4:4
            for k[6] in 0:2
                z = 0
                n = 0
                for j in 1:6
                    n = n + abs(k[j])
                    z = z + c[j]*k[j]
                end
                if z==y
                    println(z," : ",k," : ",n)
                end
            end
            end
        end
        end
    end
    end
end

foop(46)
46 : [-4, 0, 0, -1, -4, 1] : 10
46 : [-4, 0, 0, -1, 1, 0] : 6
46 : [-4, 0, 0, 1, 0, 0] : 5
46 : [1, -1, 0, -1, -4, 1] : 8
46 : [1, -1, 0, -1, 1, 0] : 4
46 : [1, -1, 0, 1, 0, 0] : 3
46 : [1, 1, -1, -1, -4, 1] : 9
46 : [1, 1, -1, -1, 1, 0] : 5
46 : [1, 1, -1, 1, 0, 0] : 4
46 : [1, 1, 4, 0, 0, 0] : 6

ここまでくるのに2時間くらいかかったので,とてもじゃないけれど自分の場合60分で大問4問も解けそうにはない。ループ変数を配列にするなんていうのは初めての経験だった。


写真:日本の通常硬貨(造幣局から引用)