シェルスクリプトマガジン

test

Pythonあれこれ(Vol.75掲載)

投稿日:2021.11.25 | カテゴリー: コード

著者:飯尾 淳

本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温かく見守ってください。皆さんと共に勉強していきましょう。第5回は、「Google Colaboratory」というクラウドサービスで、対話的にPythonコードを実行する方法を紹介します。

シェルスクリプトマガジン Vol.75は以下のリンク先でご購入できます。

図13 タートルグラフィックスで幾何学模様を描くPythonコード

from ColabTurtle.Turtle import *
initializeTurtle(initial_speed=10)
color('red')
bgcolor('white')
width(1)
x0 = pos()[0]
y0 = pos()[1]
while True:
  forward(200)
  left(170)
  if abs((pos()[0]-x0)**2 + (pos()[1]-y0)**2) < 1: break

図19 指定ファイルの各行をリストとして読み込み、その内容を表示するPythonコード

with open('/content/drive/MyDrive/TSdata.csv') as f:
  while True:
  line = f.readline().rstrip()
  if line == '': break
  print(line.split(','))

香川大学SLPからお届け!(Vol.75掲載)

投稿日:2021.11.25 | カテゴリー: コード

著者:平西 宏彰

 プログラミング言語で記述されたプログラムを解釈して、実行可能な形式に変換するのがコンパイラの役割です。コンパイラは、簡単なものであれば200行程度のコードで作成できます。今回は、整数の四則演算用の数式を処理できるコンパイラを作成します。

シェルスクリプトマガジン Vol.75は以下のリンク先でご購入できます。

図4 「main.go.y」ファイルに最初に記述するコード

%{
package main
import (
  "fmt"
  "log"
  "strconv"
  "github.com/llir/llvm/ir"
  "github.com/llir/llvm/ir/constant"
  "github.com/llir/llvm/ir/types"
  "github.com/llir/llvm/ir/value"
)
%}
%%
%%
type Node struct { // 構文木
  ID string        // 構文の種類
  Value string     // 構文が持つ値
  Left *Node
  Right *Node
}
type Lexer struct { // 字句解析器
  src string  // ソースコード
  index int   // 調査中のインデックス
  node *Node  // 構文木
}
func (l *Lexer) Error(err string) { // エラー処理
  log.Fatal(err)
}
func main() {
  var code string
  fmt.Scan(&code) // コード入力
  lexer := &Lexer{src: code, index: 0} // 字句解析
  yyParse(lexer) // 構文解析
  generator(lexer.node) // コード生成
}

図5 「main.go.y」ファイルの宣言部に追加するコード

%union {
  num int
  ope string
  node *Node
}
%type<node> program expr
%token<num> NUMBER
%token<ope> ADD SUB MUL DIV
%left ADD, SUB
%left MUL, DIV

図6 「main.go.y」ファイルのプログラム部に追加するコード

func (l *Lexer) Lex(lval *yySymType) int {
  if len(l.src) <= l.index { return -1 }
  c := l.src[l.index]
  l.index++
  if c == '+' { return ADD }
  if c == '-' { return SUB }
  if c == '*' { return MUL }
  if c == '/' { return DIV }
  if '0' <= c && c <= '9' {
    la := l.index
    for la < len(l.src) && '0' <= l.src[la] && l.src[la] <= '9' {
      la++
    }
    num, _ := strconv.Atoi(l.src[l.index-1:la])
    lval.num = num
    l.index = la
    return NUMBER
  }
  return -1
}

図7 「main.go.y」ファイルの規則部に記述するコード

program // 構文解析を開始するための構文
  : expr {
    $$ = $1
    yylex.(*Lexer).node = &Node{} // nodeの初期化
    // 式の構文解析で生成された構文木をprogram構文に
    yylex.(*Lexer).node = $$ }
expr // 式の構文
  : NUMBER { // 生成規則が数値のときの動作を記述
    $$ = &Node{
      ID: "NUMBER",
      Value: strconv.Itoa($1),
    }
  }
  | expr ADD expr {
    $$ = &Node{
      ID: "expr",
      Value: "+",
      Left: $1, // 左の式
      Right: $3, // 右の式
    }
  }
  | expr SUB expr { 
    $$ = &Node{
      ID: "expr",
      Value: "-",
      Left: $1,
      Right: $3,
    }
  }
  | expr MUL expr { 
    $$ = &Node{
      ID: "expr",
      Value: "*",
      Left: $1,
      Right: $3,
    }
  }
  | expr DIV expr { 
    $$ = &Node{
      ID: "expr",
      Value: "/",
      Left: $1,
      Right: $3,
    }
  }

図8 「main.go.y」ファイルのプログラム部に追加するコード

func generator(node *Node) {
  m := ir.NewModule()
  main := m.NewFunc("main", types.I32)
  block := main.NewBlock("")
  block.NewRet(calc(block, node))
  fmt.Println(m.String())
}
func calc(block *ir.Block, node *Node) value.Value {
  if node.ID == "expr" { return expr(block, node) }
  if node.ID == "NUMBER" { return number(node) }
  log.Fatal("error: generator")
  return nil
}
func number(node *Node) value.Value {
  val, ok := strconv.Atoi(node.Value)
  if ok != nil {
    log.Fatal("error: generator")
    return nil
  }
  return constant.NewInt(types.I32, int64(val))
}
func expr(block *ir.Block, node *Node) value.Value {
  if node.Left == nil || node.Right == nil {
    log.Fatal("error: generator")
    return nil
  }
  left := calc(block, node.Left)
  right := calc(block, node.Right)
  if node.Value == "+" { return block.NewAdd(left, right) }
  if node.Value == "-" { return block.NewSub(left, right) }
  if node.Value == "*" { return block.NewMul(left, right) }
  if node.Value == "/" { return block.NewUDiv(left, right) }
  log.Fatal("error: generator")
  return nil
}

機械学習ことはじめ(Vol.75掲載)

投稿日:2021.11.25 | カテゴリー: コード

著者:川嶋 宏彰

本連載では、機械学習の基礎となるさまざまな手法の仕組みや、それらの手法のPythonでの利用方法を解説していきます。今回は、入力データがどのようなクラス(カテゴリ)であるかを予測する分類の問題を扱います。

シェルスクリプトマガジン Vol.75は以下のリンク先でご購入できます。

図2 データセットの読み込みから、散布図のプロットまでを実施するPythonコード

import seaborn as sns
import matplotlib.pyplot as plt

plt.rcParams['font.size'] = 14
penguins = sns.load_dataset('penguins')
# 取り出す特徴量
features = ['bill_depth_mm', 'body_mass_g']  # (★)
# features = ['bill_depth_mm', 'bill_length_mm']  # 取り出す特徴量を変える
# 対象とするペンギン種
target_species = ['Adelie', 'Gentoo']  # (★)
# target_species = ['Adelie', 'Chinstrap', 'Gentoo']  # 3種のペンギンにする
# 今回用いる特徴量をクラスラベルと共に取り出す
df = penguins[['species'] + features].copy()
df.dropna(inplace=True)  # NaN が含まれる行は削除
# 今回用いるペンギン種のみとする
df2 = df[df['species'].isin(target_species)].copy()
print(df2.shape)  # (274, 3) と表示される
# 現在のパレットから用いる種 (target_species) に合わせたパレットを作成
palette = {c: sns.color_palette()[k] for k, c
           in enumerate(df['species'].unique()) if c in target_species}
fig = plt.figure(figsize=(5, 5))
sns.scatterplot(data=df2, x=features[0], y=features[1],
                hue='species', palette=palette)
plt.show()

図3 ロジスティック回帰の準備をするPythonコード

from sklearn.linear_model import LogisticRegression
import numpy as np

X = df2[features].values   # 各個体の2次元特徴量(行数 = 個体数)
y = df2['species'].values  # 各個体のクラスラベル
clf_lr = LogisticRegression(penalty='none')  # 分類モデルの準備

図4 特徴量一つ(体重)のみでロジスティック回帰をするPythonコード

f_idx = 1  # 用いる特徴量のインデックス
# 指定した列(特徴量)だけ取り出して学習
clf_lr.fit(X[:, [f_idx]], y)
# 学習されたパラメータを表示
w0 = clf_lr.intercept_[0]
w1 = clf_lr.coef_[0][0]
print(f'w_0 = {w0:.2f}, w_1 = {w1:.4f}, b = -w0/w1 = {-w0/w1:.2f}')
# 予測値および分類結果の可視化用グリッド
xmin = np.min(X[:, f_idx])
xmax = np.max(X[:, f_idx])
xs = np.linspace(xmin - (xmax - xmin) / 10,
                 xmax + (xmax - xmin) / 10, 100)  # 等間隔に100点用意
fig = plt.figure(figsize=(10, 5))
# 元データのプロット
sns.scatterplot(x=X[:, f_idx], y=(y=='Gentoo'), hue=y, palette=palette)
# 予測値(事後確率)の曲線をプロット
y_pred = clf_lr.predict_proba(xs.reshape(-1, 1))[:, 1]
plt.plot(xs, y_pred, c=palette['Gentoo'])
plt.ylim(-0.1, 1.1)
plt.xlabel(f'x ({features[f_idx]})')
plt.ylabel('y')
plt.grid()
plt.show()

図6 特徴量二つ(くちばしの高さと体重)でロジスティック回帰をするPythonコード

import matplotlib as mpl
from sklearn.preprocessing import StandardScaler

def plot_decision_boundary(X, y, clf, xylabels=None, palette=None, fig=None, ngrid=50):
  """ 分類器 clf の決定境界を描画 """
  if fig is None: fig = plt.figure(figsize=(5, 5))
  else: plt.figure(fig.number)
  # 2次元空間にグリッド点を準備
  xmin = X.min(axis=0)  # 各列の最小値
  xmax = X.max(axis=0)  # 各列の最大値
  xstep = [(xmax[j]-xmin[j]) / ngrid for j in range(2)]  # グリッドのステップ幅
  xmin = [xmin[j] - 8*xstep[j] for j in range(2)]  # 少し広めに
  xmax = [xmax[j] + 8*xstep[j] for j in range(2)]
  aranges = [np.arange(xmin[j], xmax[j] + xstep[j], xstep[j]) for j in range(2)]
  x0grid, x1grid = np.meshgrid(*aranges)
  # 各グリッド点でクラスを判定
  y_pred = clf.predict(np.c_[x0grid.ravel(), x1grid.ravel()])
  y_pred = y_pred.reshape(x0grid.shape)  # 2次元に
  y_pred = np.searchsorted(np.unique(y_pred), y_pred)  # 値をインデックスに
  clist = palette.values() if type(palette) is dict else palette
  cmap = mpl.colors.ListedColormap(clist) if palette is not None else None
  plt.contourf(x0grid, x1grid, y_pred, alpha=0.3, cmap=cmap)
  sns.scatterplot(x=X[:, 0], y=X[:, 1], hue=y, palette=palette)
  plt.legend()
  plt.xlim([xmin[0], xmax[0]])
  plt.ylim([xmin[1], xmax[1]])
  if xylabels is not None:
    plt.xlabel(xylabels[0])
    plt.ylabel(xylabels[1])
  return fig

Xs = StandardScaler().fit_transform(X)  # 標準化によるスケーリング
clf_lr.fit(Xs, y)  # 二つの特徴量を両方用いて学習
print('w0:', clf_lr.intercept_)
print('w1, w2:', clf_lr.coef_)
xylabels = [s + ' (standardized)' for s in features]  # 軸ラベル変更
plot_decision_boundary(Xs, y, clf_lr, xylabels, palette, ngrid=100)  # 決定境界
plt.show()

図9 ロジスティック回帰による各点での予測値をプロットするPythonコード

from matplotlib import cm
from mpl_toolkits.mplot3d import axes3d

# メッシュで
def gen_2dgrid(X):
  """ 2次元メッシュグリッドの生成 """
  d = X.shape[1]
  xmin = X.min(axis=0)  # 各列の最小値
  xmax = X.max(axis=0)  # 各列の最大値
  xstep = [(xmax[j]-xmin[j]) / 100 for j in range(d)]  # グリッドのステップ幅
  xmin = [xmin[j] - 10*xstep[j] for j in range(d)]  # 少し広めに
  xmax = [xmax[j] + 10*xstep[j] for j in range(d)]
  aranges = [np.arange(xmin[j], xmax[j] + xstep[j], xstep[j]) for j in range(2)]
  return np.meshgrid(*aranges)  # d=2のときは (x0grid, x1grid) が返る
# 2次元の場合の予測値 (proba)
def proba_2dgrid(clf, x0grid, x1grid):
  """ 2次元メッシュの各点での予測値を計算 """    
  return clf.predict_proba(np.c_[x0grid.ravel(), x1grid.ravel()])[:, 1]
                          .reshape(x0grid.shape)
xgrid_2d = gen_2dgrid(Xs)  # xgrid_2d: (x0grid, x1grid) のような二つ組
proba_2d = proba_2dgrid(clf_lr, *xgrid_2d)  # 予測値
# 3次元プロット
fig = plt.figure(figsize=(14, 8))
ax = fig.add_subplot(111, projection='3d')
cmap = cm.winter  # カラーマップを設定
ax.plot_surface(*xgrid_2d, proba_2d, cmap=cmap)
# ax.set_box_aspect((3, 3, 1))  # matplotlib のバージョンが3.3以上で利用可能
ax.set_zlim(-0.1, 1.1)
ax.set_xlabel(xylabels[0])
ax.set_ylabel(xylabels[1])
ax.set_zlabel('y')
ax.set_zticks([0, 0.5, 1.0])
ax.view_init(elev=60, azim=-120)  # 3次元プロットの表示角度の設定
plt.show()

図12 線形SVM による学習と決定境界の表示をするPythonコード

from sklearn.svm import SVC

C = 10  # 大きいほどハードマージンに近い
clf_lin = SVC(kernel='linear', C=C)
clf_lin.fit(Xs, y)
# 決定境界とサポートベクターを可視化
plot_decision_boundary(Xs, y, clf_lin, xylabels, palette, ngrid=100)
plt.scatter(clf_lin.support_vectors_[:, 0], clf_lin.support_vectors_[:, 1],
            s=50, facecolors='none', edgecolors='r')
plt.title(f'SVM(linear) C = {C}')
plt.show()

図17 非線形SVMとパラメータCの関係を示すPythonコード

from sklearn.datasets import make_moons

X_moon, y_moon = make_moons(n_samples=100, noise=0.2, random_state=6)
palette_o = {k: sns.color_palette()[k] for k in range(2)}
# moonデータの散布図をプロット
plt.figure(figsize=(5, 5))
sns.scatterplot(x=X_moon[:, 0], y=X_moon[:, 1],
                hue=y_moon, palette=palette_o)
plt.show()
# 異なるCでSVM(RBFカーネル)の学習と決定境界の表示
for C in [0.1, 10, 10000]:
  clf_rbf = SVC(C=C, kernel='rbf')  # kernel='rbf'は省略可能
  clf_rbf.fit(X_moon, y_moon)
  # 決定境界をプロット
  plot_decision_boundary(X_moon, y_moon,
                         clf_rbf, None, palette_o, ngrid=100)
  plt.title(f'SVM(rbf) C = {C}')
  plt.show()

図20 グリッドサーチをするPythonコード

from sklearn.model_selection import cross_val_score

best_score = -1
for gamma in [0.1, 0.5, 1, 2, 10]:  # 5通り
  for C in [0.1, 1, 10, 100, 1000, 10000]:  # 6通り
    print(f'gamma: {gamma},\tC: {C}', end='')
    svm = SVC(gamma=gamma, C=C)
    cv_scores = cross_val_score(svm, X_moon, y_moon, cv=5)
    score = np.mean(cv_scores)
    print(f'\t | average: {score:.2} <- {cv_scores}')
    if score > best_score:
      best_score = score
      best_params = {'C': C, 'gamma': gamma}
print('best_score:', best_score)
print('best_params:', best_params)
clf_rbf = SVC(**best_params)
clf_rbf.fit(X_moon, y_moon)
plot_decision_boundary(X_moon, y_moon,
                       clf_rbf, None, palette_o, ngrid=100)
title = f"C = {best_params['C']}, gamma = {best_params['gamma']}"
plt.title(title)
plt.show()

Raspberry Piを100%活用しよう(Vol.75掲載)

投稿日:2021.11.25 | カテゴリー: コード

著者:米田 聡

小型コンピュータボード「Raspberry Pi」(ラズパイ)向けにさまざまな拡張ボードが発売されています。その拡張ボードとラズパイを組み合わせれば、ラズパイでいろいろなことが簡単に試せます。第8回は、色を認識できるカラーセンサーを搭載する拡張基盤を扱います。

シェルスクリプトマガジン Vol.75は以下のリンク先でご購入できます。

図4adrszCS_CSmode_sample.pyの変更箇所

(略)
import json
import RPi.GPIO as GPIO
LED = 18

i2c = smbus.SMBus(1)
(略)
        #while True:
                GPIO.setmode(GPIO.BCM)
                GPIO.setup(LED, GPIO.OUT)
                GPIO.output(LED, GPIO.HIGH)
                time.sleep(1)   # LED点灯
(略)
                print(out_msg)
                GPIO.cleanup(LED)
(略)

特別企画 ラズパイで作る簡単VPN環境(Vol.75記載)

投稿日:2021.11.25 | カテゴリー: コード

著者:魔法少女

職場と自宅のネットワークをインターネット経由で安全につなぐ方法として「VPN」(Virtual Private Network)があります。本企画では、小型コンピュータボード「Raspberry Pi」を利用して誰でも簡単にできるVPN環境構築方法を紹介します。

シェルスクリプトマガジン Vol.75は以下のリンク先でご購入できます。

図43 NAPTの追記

[Interface]
PrivateKey = XXXXXXXXXXXXXXXXXXXXX=
Address = 10.6.0.1/24
MTU = 1420
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

特集2 Javaの最新動向(Vol.75記載)

投稿日:2021.11.25 | カテゴリー: コード

著者:伊藤 智博

エンタープライズシステムの分野で活用されている、プログラミング言語および開発・実行環境の「Java」。開発元である米旧Sun Microsystems社の買収、OpenJDKとしてのオープンソース化など、さまざまな変化がありました。本特集では、Javaの最新動向について分かりやすく解説します。

シェルスクリプトマガジン Vol.75は以下のリンク先でご購入できます。

図13 HelloWorld.javaのソースコード

public class HelloWorld {
  public static void main(String... args) {
    String message = "Hello World";
    System.out.println(message);
  }
}

図17 GreetingResource.javaのソースコード

package org.acme;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello RESTEasy";
    }
}

図20 変更後のソースコード

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
    return "Hello World";
}

図23 NullPointerExceptionが発生するコード

public class NullPo {
    public static void main(String[] args) {
        Object o = createObject();
        o.toString();
    }
    
    private static Object createObject(){
        return null;
    }
}

図26 HTMLによるコード

<html>
    <body>
        <p>Hello, world</p>
    </body>
</html>

図27 HTMLによるコードをJavaでエスケープと結合で実装

String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello, world</p>\n" +
              "    </body>\n" +
              "</html>\n";

図28 HTMLによるコードをテキストブロックで実装

String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;

シェルスクリプトマガジンvol.75 Web掲載記事まとめ

投稿日:2021.11.25 | カテゴリー: コード

004 レポート Windows 11の導入メディア作成
005 レポート YouTube配信に便利なOBS Studio
006 NEWS FLASH
008 特集1 Windows 11 徹底解説/三沢友治
022 特集2 Javaの最新動向/伊藤智博 コード掲載
036 特集3 Debian 11の新機能&改善点/やまねひでき
044 特別企画 ラズパイで作る簡単VPN環境/魔法少女 コード掲載
058 Raspberry Piを100%活用しよう/米田聡 コード掲載
061 Hello Nogyo!
062 機械学習ことはじめ/川嶋宏彰 コード掲載
072 テレワーク/桑原滝弥、イケヤシロウ
074 Pythonあれこれ/飯尾淳  コード掲載
080 タイ語から分かる現地生活/つじみき
084 法林浩之のFIGHTING TALKS/法林浩之
086 中小企業手作りIT化奮戦記/菅雄一
090 香川大学SLPからお届け!/平西宏彰   コード掲載
096 Bash入門/大津真
104 Techパズル/gori.sh
105 コラム「システムエンジニアを育てる」/シェル魔人

Vol.75

投稿日:2021.11.25 | カテゴリー: バックナンバー

 2021年10月5日、Windowsの新版である「Windows 11」がリリースされました。約6年ぶりとなるメジャーアップデートです。特集1では、このWindows 11の新機能や改善点、Windows 10からのアップデート方法について詳しく紹介します。また、Windowsが備える注目のLinux環境「Windows Subsystem for Linux 2」(WSL 2)に関してもWindows 11での更新内容に触れます。
 特集2では、Javaの最新動向について解説します。Javaが正式にリリースされてから約25年がたちました。開発元の米旧Sun Microsystems社の買収、OpenJDKやJakarta EEへのオープンソース化、オンプレミスからクラウドへの変化――など、Javaを取り巻く環境が大きく変わってきています。これらを含めて、現状のJava環境を分かりやすく紹介します。
 特集3では、2021年8月に正式リリースされたLinuxディストリビューションの新版「Debian 11」の新機能と改善点を解説します。併せて、Debian 11を使い始めたい人や、旧版のDebian 10から更新したい人向けにインストールおよび更新の手順も紹介します。
 特別企画では、小型コンピュータボード「Raspberry Pi」を使用してVPN(Virtual Private Network)環境を簡単に構築する方法を解説します。利用するVPNソフトは「WireGuard」です。WindowsやmacOS、Android、iOSを搭載した機器からVPNを利用できます。
 このほかに、連載「Raspberry Piを100%活用しよう」では、カラーセンサー搭載ボードを扱います。連載「タイ語から分かる現地生活」では、タイ王国におけるバイクや車の乗り方について紹介します。今回も読み応え十分のシェルスクリプトマガジン Vol.75。お見逃しなく!

※記事掲載のコードはこちら。記事の補足情報はこちら

※読者アンケートはこちら

Vol.75 補足情報

投稿日:2021.11.25 | カテゴリー: コード

特別企画 ラズパイで作る簡単VPN環境

p.48の『ユーザー名の「pi」を入力して[Enter]キーを押します。』の後に『「Password:」が表示されたら、パスワードの「raspberry」を入力して[Enter]キーを押します。』が抜けていました。お詫びして訂正いたします。

情報は随時更新致します。

  • shell-mag ブログの 2021年11月 のアーカイブを表示しています。

  • -->