なんじゃくにっき

プログラミングの話題中心。

S&P 500のグラフをGoogle ColabのAIに描かせる

最近、自然言語処理(とちょっと機械学習)絡みで遊んでいて、 Google Colaboratory使うことがあるんですが、

新規ノートブックで最初に「コーディングを開始するか、AIで生成します」 と出てくるので何かに使えないかと思った次第。(以前AIなんてついてなかったよね?)

で、新NISAもはじまったことだし(てもう2ヶ月以上経ってますが)S&P 500のグラフでも描いてくれるかな?

と思ったので試してみます。

プロンプトは"S&P 500のデータをグラフで出してください。期間は10年、y軸は対数で出してください。"

!pip install yfinance
import yfinance as yf

# Download the historical data for the S&P 500 index
data = yf.download('^GSPC', period='10y')

# Plot the closing prices on a logarithmic scale
data['Close'].plot(logy=True)

# Add a title and axis labels
plt.title('S&P 500 Index: 10-Year Historical Data')
plt.xlabel('Date')
plt.ylabel('Closing Price (Log Scale)')

# Show the plot
plt.show()

実行結果

いやー素晴らしい、タイトルも付けてくれるし今までExcel芸でやってたのが馬鹿みたいですね。

Google検索の結果から特定のドメインを除外する方法2つ

やりたいこと

Google検索の結果の上位に役立たない記事が出てきて、これを出さなくしたい。

ドメイン単位

検索クエリに除外したいドメインを指定する

"-site" 指定でドメインを除外できます。

例えば”はてな”というキーワードで検索するときにhatena.ne.jpのドメインのものを除外したいときはキーワードを以下のようにします。

"はてな -site:hatena.ne.jp"

欠点 - わざわざ毎回入力が面倒(URLを作成するツールを自分で作れば良いんですが・・) - サイトをたくさん入力するとクエリが長くなる

CSSを使って隠す

FirefoxChromeの拡張のStylusを使ってCSSを無理やり当てて隠すことができます。

Stylus – 🦊 Firefox (ja) 向け拡張機能を入手

なお、CSSを当てられれば他の拡張機能でも大丈夫です。

#search > div > div > div > div, .ULSxyf, div[id^="arc-srp"] {
  /* 検索結果から特定ドメインのものを除外 */
  &:has(a[href*="https://twitter.com"]) { display: none; }
}

欠点 - マークアップが変わると効かなくなってしまう - 通信量自体は減らない - 隠しているだけなので1ページ目に何も出てこず、”もっと見る”を押すまで何もないことがある

おまけ

Googleの検索結果をつめてみました。

.srp {
  --center-abs-margin: 100px;
}

#rcnt {
    width: 100%;
    display: block;
    
    > div {
        width: 100%;
    }
}

/* 他の検索 */
div[data-smqc="4"] {
    display: none;
}

#taw {
  margin-left: 200px;
  margin-top: -44px;
}

cite, br {
    display: none;
}

.g {
    width: 100% !important;
    margin-bottom: 16px !important;
}

#search h3, .ULSxyf h3, div[id^="arc-srp"] h3
{
    margin-top: 0;
    margin-left: 250px;
    font-size: large;

    & + div {
        width: 246px;
        overflow-x: hidden;
    }
}

#search table h3 {
    margin-left: 0;    
}

#search > div > div > div > div, .ULSxyf, div[id^="arc-srp"] {
  margin-bottom: 0;
  svg { display: none}

  > div {
      margin-bottom: 0;
  }
    
  > div > div > div > div {
    margin-bottom: 0;
  }

  /* 関連性の高い検索 */
  &:has(a[href*="/search"]) { display: none; }

  /* 検索結果から特定ドメインのものを除外 */
  &:has(a[href*="https://twitter.com"]) { display: none; }
}
    

ルーターを買いかえた / エイスース ASUS RT-AX59U

ルーターを買い替えました。ASUSのを買いました。

↓ ヨドバシのリンク。アフィリエイトではありません。

https://www.yodobashi.com/product/100000001008022223/

エイスース ASUS Wi-FiルータWi-Fi 6(11ax)対応 3603+574Mbps AX4200 デュアルバンド Aiメッシュルーター [RT-AX59U]

買い替えた理由

ルーターで広告ブロックをしたくなったからです。

サイト運営の費用を賄うために広告を出してるのはわかるし、広告が目に入るのはしょうがないなーと今まで思ってたんですが、

フィッシング詐欺やスクロール阻害など、広告業界自体に自浄作用がないことは明らかで、健全ではないと思ったのでブロックすることにしました。

スマホChromeなどではブラウザ拡張が使えないのでルーターでブロックすることにしました。

端末複数持っていても一個一個設定せずに一回で設定が済みますし。

で、今まで持っていたルーターがURLブロック機能を持っていなかったからです。

ルーターの探し方

URLブロック機能を持っているルーターに絞って探し始めたんですが、

最近のルーターだとブロック機能は別途有料だったり最初の何年か無料でその後有料だったり。

別に有料のものでもそんなに高くないし良いかなと少し思いましたが、そのうち機種がサービスの対象外になったりしたら嫌だなと思って、別途サービスが必要にないものにしました。

また、AIで判定するのもありましたが別にドメイン直指定で良いな、と。

いうことでASUSのにしました。

ブロック

以前のASUSの製品だとFirewallのURLフィルタのブラックリストに入れられるのは確か10個とか20個とかだったと思うんですが、64個までになってて良かったです。

10個だとちょっと足りないかなーって感じで20個あれば大体良い気もしますが。

でいくつかブロックしてみるとWebページの動作が軽い。ネットワークやらjsの動作やらが減って軽くなったおかげ。

たまにjsの読み込みのところでブロックされて遅くなるサイトもありますがご愛嬌。

思うところ

私のように悪いことをして広告ブロックする人が増えてくると対策されていくのかもしれないなーっと。

例えば

  • 広告配信自体をコンテンツと同ドメインから配信する
  • 広告配信のドメインを頻繁に(or 動的に切り替える)
  • 広告ブロックされているとコンテンツを見えなくする(これは今でもたまにありますが)

などなど。とはいえ費用対効果もあるので今のところはあまり見かけないですね。

注意点

動作が不安定との口コミがありますが、発売当初はそうだったみたいです。

購入したらまずファームウェアをアップデートしたほうが良いと思います。

今の所自分の環境では問題は発生していません。

言語処理100本ノック を解いてみる

言語処理100本ノックを解いていきます。

言語処理100本ノック 2020 (Rev 2) - NLP100 2020

解くのに使ったプログラミング言語Python 3。

なるべく関数型言語チックに書いているつもりです。再代入はなるたけ避ける。

解答はgithubにも載せておきます。

GitHub - nanjakkun/nlp_100_ans: 言語処理100本ノックの解答

1章の答えと解説だけこの記事にも載せます。

全部解説書こうと思ったけど力尽きたのでgithub見てください・・

(3/24現在 40問まで終了)

1章 準備運動の解答

00

文字列”stressed”の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.

str = "stressed"[::-1]
print(str)

sliceの使い方を知っていれば一瞬。[start:stop:step]。

他言語から来るとstrにreverseってメソッドが欲しくなるかも。

01

「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

str = "パタトクカシーー"[::2]
print(str)

これも前問と同様sliceの使い方知ってれば。

02

「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

itr = map(lambda x: x[0] + x[1], zip("パトカー", "タクシー"))
print("".join(itr))

zip使いましょう。

03

“Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.”という文を単語に分解し, 各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

import re

str1 = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
itr1 = map(lambda str: len(str), re.split(r'[\s,\.]+', str1))
itr2 = filter(lambda x: x > 0, itr1)
print(list(itr2))

04

"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.” という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字, それ以外の単語は先頭の2文字を取り出し, 取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

import re

str1 = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

def to_elemnt_symbol(itr) -> str:
  idx = itr[0]
  if (idx in [1, 5, 6, 7, 8, 9, 15, 16, 19]):
    return itr[1][0], idx
  else:
    return itr[1][0:2], idx

itr1 = filter(lambda x: len(x) > 0, re.split(r'[\s,\.]+', str1))
itr2 = map(to_elemnt_symbol, enumerate(itr1, 1))

print(dict(itr2))

他言語だとmapWithIndexみたいなのを使うところはPythonではenumerate。

05

与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ. この関数を用い,”I am an NLPer”という文から単語bi-gram,文字bi-gramを得よ.

def word_n_gram(text, num=2):
  words = text.split(" ")
  return list(map(lambda i: words[i:i+num], range(len(words))))

def char_n_gram(text, num=2):
  words = text.replace(" ", "")
  return list(map(lambda i: words[i:i+num], range(len(words))))

text1 = "I am an NLPer"

print(word_n_gram(text1, 2))
print(char_n_gram(text1, 2))

06

paraparaparadise”と”paragraph”に含まれる文字bi-gramの集合を, それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ. さらに,’se’というbi-gramがXおよびYに含まれるかどうかを調べよ.

# 前回の問題で使ったのと同じ関数
def char_n_gram(text, num=2):
  words = text.replace(" ", "")
  return list(map(lambda i: words[i:i+num], range(len(words))))

text1 = "paraparaparadise"
text2 = "paragraph"

X = set(char_n_gram(text1))
Y = set(char_n_gram(text2))

print("union: ", X | Y)
print("intersect: ", X & Y)
print("diff: ", X - Y)

if "se" in X:
  print("X contains se")

if "se" in Y:
  print("Y contains se")

Set使いましょう。

07

引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ. さらに,x=12, y=”気温”, z=22.4として,実行結果を確認せよ.

def weather(x: int, y: str, z: float) -> str:
  return f'{x}時の{y}は{z}'

print(weather(12, "気温", 22.4))

文字列に変数展開する方法はいくつかあるけどその1つ。

08

与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ. - 英小文字ならば(219 - 文字コード)の文字に置換 - その他の文字はそのまま出力 この関数を用い,英語のメッセージを暗号化・復号化せよ.

def cipher(text: str) -> str:
  def transform_char(ch):
    if (97 < ord(ch) & ord(ch) < 122):
      return chr(219 - ord(ch))
    else:
      return ch

  return "".join(list(map(transform_char, text)))

text1 = "lorem ipsum"
print(cipher(text1))
print(cipher(cipher(text1)))

decodeとencodeが同じ関数なんですねえ。2回同じのを作用させると元に戻る。

09

スペースで区切られた単語列に対して,各単語の先頭と末尾の文字は残し, それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ. ただし,長さが4以下の単語は並び替えないこととする. 適当な英語の文(例えば”I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind .”)を与え, その実行結果を確認せよ.

import random

def typoglycemia(text) -> str:
  def shuffle(word) -> str:
    if (len(word) <= 4):
      return word
    else:
      substr = word[1:-1:]
      return word[0] + "".join(random.sample(substr, len(substr))) + word[-1]

  words = text.split(" ")
  return " ".join(map(shuffle, words))

text1 = "I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
print(typoglycemia(text1))

以前流行ったアレですね。

この ぶんょしう は イリギス の ケブンッリジ だがいく の けゅきんう の けっか 、 にんんげ は もじ を にしんき する とき その さしいょ と さいご の もさじえ あいてっれば じばんゅん は めくちちゃゃ でも ちんゃと よめる という けゅきんう に もづいとて わざと もじの じんばゅん を いかれえて あまりす。

余談

ChatGPT(3.5)に解けるのかと思って問題を与えてみたら、大体解けますね。ちょっと間違ってたりするけど。

と言ってもこれは解答をネットにアップしている人は他にもいるので、まあ、って感じではありますが。

速度的には自分で書くより向こうのほうがずっと速いのでこちらの完敗でございます。

reCAPTCHAとか画像認証をやめてほしい

題意のとおりreCAPTCHAや画像認証をやめてほしい。

Webサービスで何かのステップの先に進もうとすると人力で画像を読み取って入力しないといけないやつね。

読みづらくした文字を読み取って入力させたり、この◎◎枚の絵の中から●が描かれたものを選べ、みたいなやつ。

正直あの手のものが苦手で、何度も失敗することがよくある。

セキュリティを担保するんだったら他段階認証とかにしてほしい。ログインが必要なサービスだったらそっちのほうが安全だし利用者に負担がかからないと思う。

画像認証なんて攻撃者がちょっと本気を出せば突破できるものだし。

ログイン不要でコメントできるサービスでbotを防ぐのには多少効果があるのかはしれない。

VSCodeのextention Ruby LSP

VSCodeRuby用ExtentionとしてはVSCode Ruby を使っていたんですが、Ruby LSPへの乗り換えを勧められるので乗り換えました。

VSCode Ruby - Visual Studio Marketplace

Ruby LSP

Ruby LSP - Visual Studio Marketplace

VSCodeのextention画面からRuby LSPインストールします。

Multi-root workspaces

Ruby LSPをインストールしてもそのままでは動きません。

なんか”Lockfileがプロジェクト直下に見当たらないよ”的なエラーメッセージが出ます。

VSCodeのMulti-root workspacesを有効にしろと言ってきます。

(なお、1 Workspaceに1 root = 1 projectの場合にはそのまま動くと思います)

workspacesをMulti-rootにするには、workspace直下の.code-workspaceを編集します。

{
    "folders": [
        {
            "path": "."
        }
    ],
}

上記のようにrootが直下1つになっているのを

{
    "folders": [
        {
            "path": "project_a"
        },
        {
            "path": "project_b"
        },
    ],
}

のようにします。

気を付ける点

Ruby 3.0以降でないと使えないです。

Ruby 2.7以前のプロジェクトを触らないときは効いてくれません・・

また当然ですがプロジェクトの.ruby-versionで指定されたバージョンと同じバージョンのRubyがローカルに必要です。

dockerで開発しているといなかったりするんですよねえ。

IRBの色を変えたい

なーんかRubyのREPLの色が見づらくて変えられないかなーと思っていたら変えられるとのこと。

reline/doc/reline/face.md at master · ruby/reline · GitHub

$HOME/.irbrc に

if defined? Reline::Face
  Reline::Face.config(:completion_dialog) do |conf|
    conf.define :default, foreground: :white, background: :blue
    conf.define :enhanced, foreground: :white, background: :magenta
    conf.define :scrollbar, foreground: :white, background: :blue
  end
end

relineがない環境でirbが落ちないようにinstallされているか調べています

はてなブックマークの表示を変えたい(2)

前回の続き

ちょっとCSSいじりました。

はてなブックマークの表示を改変

  • カテゴリとドメイン名をタイトルの左に移動
  • 日時とタグ非表示
  • ガタガタしてたので幅調整 など。
#entrylist-ad-right-top {
    position: absolute;
    right: 0;
    z-index: 1;
    top: 32px;
}

.entrylist-wrapper {
    width: 100%;    
}

.entrylist-contents-title {
    min-height: 0px;
    width: 400px;
    order: 2;
    padding: 0;
    margin: 0;
}

.entrylist-header-main .entrylist-image-entry .entrylist-contents-title {
    padding-right: 0;    
}

.entrylist-contents-title a {
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    font-size: small;
}

.entrylist-item {
   width: 100%;    
}

.entrylist-header-main, .entrylist-item>li {
    flex-basis: auto;
    max-width: 100%;
    width: 100%;
}

.entrylist-contents-body {
    max-width: 60%;
}

.entrylist-item .entrylist-image-entry .entrylist-contents-description, .entrylist-contents-description {
    text-align: left;
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    margin-bottom: 0;
}

.entrylist-contents-thumb{
    display:none;
}

.entrylist-contents-main {
    padding: 4px;
    flex-direction: row;   
}

.entrylist-contents-users {
    display: inline;
    text-transform: none;
    font-size: medium;
    right: auto;
}

.entrylist-contents-users a {
   display: inline;    
}

.entrylist-contents-users span {
    font-size: 14px;
}

.entrylist-contents-domain, .river-placement .entrylist-contents-domain {
    width: 130px;
    padding: 0.8rem 0 0 0.2rem;
    order: 1;
}

.entrylist-contents-meta {
    padding: 0;
    order: 0;
    width: 100px;
}

.entrylist-contents-meta li {
    margin-top: 20px;
}

.entrylist-contents-date {
    display: none;
}

.entrylist-contents-tags {
    display: none;
}

おまけ

特定のドメインの記事は見えなくしたい場合。

例として匿名ダイアリーを非表示にしたい場合。

li.js-keyboard-selectable-item:has(a[href="/site/anond.hatelabo.jp/"]) {
    display:none;
}

はてなブックマークの表示を変えたい(1)

はてなブックマークをPCのブラウザで見ると、1行に4つの記事が表示されていて、見るときに視線を左右に移動させないといけないのがちょっとつらい。

はてなブックマーク

1行1記事で基本上から下にだけ視線を移動させれば良いようにしたい。

ということでCSSを無理やり当てて表示を変更してみました。

改変はてなブックマークのSS
改変はてなブックマークのSS

ちょっとまだガタガタしている部分もありますが、気が向いたら直します。

やり方

StylusっていうChrome Extentionを使用しました。(Firefoxにもあります)

特定のサイトのCSSを上書きできるブラウザ拡張は他にもあるのでお好みのものをどうぞ。

CSS

.entrylist-wrapper {
    width: 100%;    
}

.entrylist-contents-title {
    min-height: 0px;
    width: 400px;
}

.entrylist-contents-title a {
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    font-size: small;
}

.entrylist-item {
   width: 100%;    
}

.entrylist-header-main, .entrylist-item>li {
    flex-basis: auto;
    max-width: 100%;
    width: 100%;
}

.entrylist-contents-body {
    width: 50%;    
}

.entrylist-item .entrylist-image-entry .entrylist-contents-description, .entrylist-contents-description {
    text-align: left;
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    margin-bottom: 0;
}

.entrylist-contents-thumb{
    display:none;
}

.entrylist-contents-main {
    padding: 4px;
    flex-direction: row;   
}

.entrylist-contents-users {
    text-transform: none;
}

.entrylist-contents-users span {
    font-size: 10.5px;
}

.entrylist-contents-domain {
    padding: 0;   
}

.entrylist-contents-meta {
    padding: 0;
}

.entrylist-contents-tags {
    max-width: 200px;
    padding: 0;
}

余談

昔々は本家はてなブックマークも1行に1記事でした。

で。それが今の表示に変わってから元の行表示がほしいユーザーがいて、その人たちに嫁のはてぶっていうサイトが人気だったんですが、そこも閉鎖してしまってました。

PDFをプログラムで編集したい

既存のPDFにテキストを追加したい・・と思ったことありませんか?

今の時期なら国税庁が配布している確定申告書等のPDFに印字したい、とかでしょうか。

確定申告書等の様式・手引き等(令和5年分の所得税及び復興特別所得税の確定申告分)|国税庁

※なお、私はe-Taxで済ませたので実際のところは確定申告書を印刷したいわけではありません

画像として編集

PDFをjpgなりpngなりのラスター画像にして編集する方法。

画像にしてしまえばいくらでも文字を載せたりすることはできます。

が、欠点としては以下の点が挙げられます

  • 出力時の解像度が低いと印刷時に汚くなる
  • 出力時の解像度が高いとファイルサイズが大きくなる
  • テキストとしての情報が失われて画像になってしまうので再度の編集が難しくなる

ライブラリ

pdf.js

GitHub - mozilla/pdf.js: PDF Reader in JavaScript

pdf.jsはJavaScriptHTML5canvasにPDFを描画するためのライブラリ。

描画してからcanvasのtoDataURLを使うとPNGを出力できるが、当然テキストの情報は失われます。

無理やりpdf.jsが内部で持っているoperationのdataをいじれば内容は編集できるが、素のPDFの情報に近く、編集するのはかなり大変。

pdf-lib

https://github.com/Hopding/pdf-lib

jsのコードからテキストを追加できます。

ただしGUIはなく、位置を指定する必要がある(単位はポイント=1/72インチ?)。また文字ごとの間隔を調整したい場合は1文字ずつ印字、になりそう。

既存テキストの編集はできません(対応したいと言っているが3年位開発止まってる)。

HummusJS/MuhammaraJS

https://github.com/julianhille/MuhammaraJS

HummusJSが開発終了してMuhammaraJSに引き継がれた。

C++製ライブラリとそのjsラッパーなのでブラウザでは動作しない(だれかWebAssembly化して・・)

PDFBox

https://pdfbox.apache.org/

Java製ライブラリ。

テキストの追加は出来る。

まとめ

コードからPDFにテキスト追加できるライブラリはいくつかありましたが、既存テキストの編集は見つけられませんでした。

また、GUIからぽちぽちしてPDFを楽に編集できる方法はオープンソースのものでは見つけられませんでした。

GUIから操作したいときはAdobeAcrobatでも買いませう。