[NumPy]正規化(Normalization)を行う

正規化とはデータを扱いやすいスケールに変更する手法です。ここでは代表的なMin-Max normalization、Z-score normalizationについて解説します。

  • Min-Max normalization
  • Z-score normalization

Min-Max normalization

正規化というとMin-Max normalizationを指すといわれることもありますが、正直そこまで気にする必要はありません。どちらかというと、正規化を行うときにデータの性質に応じて適切な手法を選択できる方が重要です。

Min-Max normalizationとは

Min-Max normalizationとは、データを最小値0、最大値1にスケールする手法です。

データ$x_i$をMin-Max normalizationで正規化した$x^{\prime}_i$は以下の式で求めます。

$$ x^{\prime}_i = \frac{x_i – min(x)}{max(x) – min(x)} \quad (i = 1, 2, \cdots , n) $$

Min-Max normalizationは外れ値に弱いという特徴があります。最小値と最大値がはっきりしている場合に適した手法です。外れ値が含まれる場合は後述のZ-score normalizationを使用する方が適しています。

NumPyによる実装

では、実際にNumPyで実装してみましょう。

まずは、正規化前の5×5の行列を作成します。再現しやすいように乱数のシードは固定しておきます。

np.random.seed(123)
x = np.random.random((5, 5))
print(x)
[[0.69646919 0.28613933 0.22685145 0.55131477 0.71946897]
 [0.42310646 0.9807642  0.68482974 0.4809319  0.39211752]
 [0.34317802 0.72904971 0.43857224 0.0596779  0.39804426]
 [0.73799541 0.18249173 0.17545176 0.53155137 0.53182759]
 [0.63440096 0.84943179 0.72445532 0.61102351 0.72244338]]

正規化前後でどう変わったかわかりやすいように最小値、最大値、平均値、標準偏差を求めておきます。

print('最小値 :%f' % np.min(x))
print('最大値 :%f' % np.max(x))
print('平均値 :%f' % np.mean(x))
print('標準偏差:%f' % np.std(x))
最小値 :0.059678
最大値 :0.980764
平均値 :0.524464
標準偏差:0.226296

式の定義どおりに実装します。np.min関数で最小値、np.max関数で最大値を求めています。

x_norm = (x - np.min(x)) / (np.max(x) - np.min(x))
print(x_norm)
[[0.02615693 0.72523256 0.32482616 0.41610292 0.11393134]
 [[0.69134813 0.24586343 0.18149608 0.53375766 0.71631841]
 [0.39456516 1.         0.67871147 0.45734477 0.36092125]
 [0.30778888 0.72671997 0.41135597 0.         0.36735576]
 [0.73643209 0.13333586 0.12569274 0.51230105 0.51260093]
 [0.62396223 0.85741574 0.72173197 0.59858193 0.71954765]]

ぱっと見で最小値0、最大値1であることはわかりますが、念のため先ほどと同じように最小値、最大値、平均値、標準偏差を確認しましょう。

print('最小値 :%f' % np.min(x_norm))
print('最大値 :%f' % np.max(x_norm))
print('平均値 :%f' % np.mean(x_norm))
print('標準偏差:%f' % np.std(x_norm))
最小値 :0.000000
最大値 :1.000000
平均値 :0.504606
標準偏差:0.245684

最小値0、最大値1であることが確認できます。加えて、若干値が違いますが、平均値と標準偏差はほとんど変わっていないことがわかります。

最小値0、最大値1にスケールする仕組みを理解する

Z-score normalizationは平均0、標準偏差1にスケールする手法になります。

わかりやすいデータを使って計算過程をひとつずつ確認して、最小値0、最大値1の範囲にスケールする仕組みを確認していきましょう。

まずは、以下のようなデータを用意します。10、20、・・・、50と10ずつ増える5個のデータです。

x = np.array([10, 20, 30, 40, 50])
print(x)
[10 20 30 40 50]

まずは分子から確認します。データから最小値を引きます。最小値は10なので、各要素から引くと以下のようになります。

print(x - np.min(x))
[ 0 10 20 30 40]

次に分母を見てみます。最大値50から最小値10を引くので、40になります。

print(np.max(x) - np.min(x))
40

すでに計算した分子の最大値は40で、分母と同じ値ですので、割り算の結果は1になります。一方で、最小値は0ですので、割り算の結果は0になります。それ以外の値は最小値と最大値の間に収まるため、計算結果はすべて0以上1以下になります。

print((x - np.min(x)) / (np.max(x) - np.min(x)))
[0.   0.25 0.5  0.75 1.  ]

Z-score normalization

次にZ-score normalizationについて確認します。標準化(Standardization)とも呼ばれることもありますが、こちらもそれほど気にする必要はありません。

Z-score normalizationとは

データ$x_i$をZ-score normalizationで正規化した$x^{\prime}_i$は以下の式で求めます。

$$ x^{\prime}_i = \frac{x_i – \bar{x}}{\sigma} \quad (i = 1, 2, \cdots , n) $$

NumPyによる実装

正規化前のデータおよび最小値、最大値、平均値、標準偏差を再掲しておきます。

np.random.seed(123)
x = np.random.random((5, 5))
print(x)
[[0.69646919 0.28613933 0.22685145 0.55131477 0.71946897]
 [0.42310646 0.9807642  0.68482974 0.4809319  0.39211752]
 [0.34317802 0.72904971 0.43857224 0.0596779  0.39804426]
 [0.73799541 0.18249173 0.17545176 0.53155137 0.53182759]
 [0.63440096 0.84943179 0.72445532 0.61102351 0.72244338]]
print('最小値 :%f' % np.min(x))
print('最大値 :%f' % np.max(x))
print('平均値 :%f' % np.mean(x))
print('標準偏差:%f' % np.std(x))
最小値 :0.059678
最大値 :0.980764
平均値 :0.524464
標準偏差:0.226296

こちらも同様に式どおりに実装します。np.mean関数が平均(算術平均)、np.std関数が標準偏差を求める関数です。

x_norm = (x - np.mean(x)) / np.std(x)
print(x_norm)
[[ 0.76008999 -1.05315055 -1.31514268  0.11865512  0.86172564]
 [-0.44789519  2.01638476  0.70865548 -0.19236556 -0.58483479]
 [-0.8010976   0.90406276 -0.37955215 -2.05387975 -0.55864464]
 [ 0.94359364 -1.51116753 -1.54227706  0.03132102  0.0325416 ]
 [ 0.48581156  1.43602912  0.88376026  0.38250702  0.87486952]]

正規化後の最小値、最大値、平均値、標準偏差を見てみましょう。

print('最小値 :%f' % np.min(x_norm))
print('最大値 :%f' % np.max(x_norm))
print('平均値 :%f' % np.mean(x_norm))
print('標準偏差:%f' % np.std(x_norm))
最小値 :-2.053880
最大値 :2.016385
平均値 :-0.000000
標準偏差:1.000000

平均値0、標準偏差1にスケールされていることがわかります。また、最小値と最大値も変わっていることにも注意してください。

平均値0、標準偏差1にスケールする仕組みを理解する

Z-scoreについても平均値0、標準偏差1にスケール仕組みをひとつずつ確認していきましょう。

データは先ほどと同じデータを使います。

x = np.array([10, 20, 30, 40, 50])
print(x)
[10 20 30 40 50]

このデータの平均は30、標準偏差は$\sqrt{200}$になります。

print('平均値 :%f' % np.mean(x))
print('標準偏差:%f' % np.std(x))
平均値 :30.000000
標準偏差:14.142136

まずは分子から見ていきます。平均値30を引くので、分子の平均値は0になります。同様に標準偏差求めると$\sqrt{200}$になっています。

print('平均値 :%f' % (x - np.mean(x)).mean())
print('標準偏差:%f' % (x - np.mean(x)).std())
平均値 :0.000000
標準偏差:14.142136

分母は分子の標準偏差と同じ$\sqrt{200}$でしたので、割った結果の標準偏差は1になります。

print((x - np.mean(x)) / np.std(x))
[-1.41421356 -0.70710678  0.          0.70710678  1.41421356]

実際に平均値と標準偏差を求めます。

print('平均値 :%f' % np.mean((x - np.mean(x)) / np.std(x)))
print('標準偏差:%f' % np.std((x - np.mean(x)) / np.std(x)))
平均値 :0.000000
標準偏差:1.000000

外れ値に弱いとはどういうことか

Min-Max normalizationは外れ値に弱いという説明をしました。これがどういうことか、Z-score normalizationなら大丈夫なのかについて具体的な例を使って確認します。

以下のような具体例を用意します。

1,000人分の身長データを使って正規化を行います。身長データは正規分布に従いますが、990件は正常データで10件は外れ値であるとします。
この外れ値は100の位の1が読み取れず欠損したデータ(180cmが80cmになってしまった)が10件あるとします。

まずは必要なパッケージをインポートします。

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

正常データを作成する

まずは正常データ990件を用意します。それっぽい身長データにするために、平均値170、標準偏差10の正規分布に従う乱数を生成します。

np.random.seed(123)
x = np.random.normal(loc=170, scale=10, size=990)

これをヒストグラムで描画してみます。

plt.hist(x, bins=100)
plt.show()

numpy.random.normal関数を使って作成したデータですので正規分布に従っています。

ではこのデータをMin-Max normalization、Z-score normalizationで正規化し、同様にグラフを出力してみましょう。

正常データをMin-Max normalizationで正規化する

まずはMin-Max normalizationを使って正規化します。

x_norm = (x - np.min(x)) / (np.max(x) - np.min(x))
plt.hist(x_norm, bins=100)
plt.show()

最小値0、最大値1にスケールしただけで分布は変わっていません。

正常データをZ-score normalizationで正規化する

次にZ-score normalizationを使って正規化してみます。

x_norm = (x - np.mean(x)) / np.std(x)
plt.hist(x_norm, bins=100)
plt.show()

こちらも中心が0になっているだけで、分布は変わっていません。

外れ値を生成して正常データに加える

では、外れ値を10件生成し、それを正常データに加えていきます。

e1 = np.random.normal(loc=170, scale=10, size=10)-100
print(e1)
[60.91733437 76.55533937 72.40244965 63.547099   73.60026527 51.22368305
 72.34040489 76.24323922 78.11939825 49.77843013]

外れ値は単純に100を引いた値を使います。

このデータを正常値に加え、念のためシャッフルしておきます。

x2 = np.concatenate([x, e1])
np.random.shuffle(x2)
plt.hist(x2, bins=100)
plt.show()

外れ値は小さい値を用意したため、グラフは右に寄った形になっています。

では、これをMin-Max normalization、Z-score normalizationで正規化してみます。

外れ値を含むデータをMin-Max normalizationで正規化する

先ほどと同様の手順で正規化してグラフを出力します。

x2_norm = (x2 - np.min(x2)) / (np.max(x2) - np.min(x2))
plt.hist(x2_norm, bins=100)
plt.show()

外れ値を含まない場合は0.2から0.8くらいの範囲にデータが分布していましたが、外れ値を含むと0.6から0.9くらいの範囲に分布していることがわかります。
もともとは0.5くらいが中心でしたが、0.7から0.8あたりに中心が来ており、データが偏っていることになります。

これが外れ値に弱い(外れ値に敏感ともいう)ということになります。

外れ値を含むデータをZ-score normalizationで正規化する

では、Z-score normalizationだとどうなるでしょうか。

x2_norm = (x2 - np.mean(x2)) / np.std(x2)
plt.hist(x2_norm, bins=100)
plt.show()

こちらもグラフ自体は偏っていますが、外れ値を含まない場合も外れ値を含む場合も-2から2の範囲に分布していることがわかります。
外れ値を含んでいますが、正規化後の分布はほとんど変わっていない、すなわち外れ値に強いということがいえます。

このことから外れ値を含む場合や外れ値を除外できない場合は、Min-Max normalizationよりもZ-score normalizationの方が適しているといえます。
ただし、外れ値のデータを除外したり、外れ値を修正・補完して、想定される最小値・最大値の範囲できるのであれば、Min-Max normalizationを使用して正規化することも可能であることも覚えておいてください。

[NumPy]単位行列を作成する(eye関数、identity関数)

NumPyで単位行列(identity matrix)を作成する2つの方法について解説します。

NumPyには、単位行列を作成する方法が2つ用意されています。

  • eye関数(numpy.eye) – N×Mの単位行列を作成する
  • identity関数(numpy.identity) – 正方行列の単位行列を作成する

N×Mの単位行列を作成するeye関数

単位行列を作成する関数としてよく見かけるのがeye関数です。以下のように書くことで単位行列を作成することができます。

# 3x3の単位行列を作成する
E = np.eye(3)
print(E)

この例では引数に3を指定することで、3×3の単位行列を作成していますが、引数をもう一つ指定することで、正方行列以外の単位行列を作ることもできます。

以下の例では引数に3と4を指定することで、3×4の単位行列を作成しています。

# 3x4の単位行列を作成する
E = np.eye(3, 4)
print(E)
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]]

正方行列の単位行列を作成するidentity関数

eye関数に比べると知名度はありませんが、正方行列の単位行列を作成することができる、identity関数も用意されています。

先ほどと同様に3×3の単位行列を作成する場合は、以下のように書きます。

# 3x3の単位行列を作成する
E = np.identity(3)
print(E)
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

どのように使い分けるのか

結論からいうと、使い分ける必要はありません。これまでどおりeye関数だけを使用していただいても、eye関数とidentity関数を使い分けても構いません。とりあえず、2つの方法があることだけは覚えておいてください。

PDBにローカルユーザーを作成する(Oracle Database 19c)

PDBにローカルユーザーの作成を行う手順について解説します。

前提

手順に使用しているデータベース環境およびCDB、PDBの設定、作成するローカルユーザーは以下のとおりです。

手順に沿ってローカルユーザーを作成する際は適宜読み替えてください。

項目
バージョンOracle Database 19c (19.3.0)
CDB
 SIDORCLCDB
PDB
 PDBローカル管理者ユーザーPDBADMIN
 PDBローカル管理者パスワードoracle
 SIDPDB1
ローカルユーザー
 ユーザーuser01
 パスワードpassword

PDBローカル管理者ユーザーにDBA権限を与える

PDBローカル管理者ユーザーを使ってローカルユーザーを作成するため、PDBローカル管理者ユーザーにDBA権限を付与します。

PDBローカル管理者ユーザーの権限を確認する

まずはCDBにOS認証でCDBに接続しますが、ORACLE_SID環境変数が必要となるため、ORACLE_SID環境変数を確認します。

$ echo $ORACLE_SID

この環境はDocker上に構築したOracle Database 19cですが、ログインしてみるとORACLE_SID環境変数は設定されていませんでした。

ORACLE_SID環境変数を設定してSQL*Plusを起動します。

$ ORACLE_SID=ORCLCDB sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Sat Mar 19 14:36:24 2022
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> 

念のため、CDBに接続出来ていることを確認しましょう。

SQL> show con_name

CON_NAME
------------------------------
CDB$ROOT
SQL> 

PDBについても確認します。今回はすでに作成済みのPDBであるPDB1にローカルユーザーを作成していきます。

SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 PDB1                           READ WRITE NO
SQL> 

PDB1に切り替えます。

SQL> alter session set container=pdb1;

Session altered.

SQL> 

PDB1に切り替わったことを確認します。

SQL> show con_name

CON_NAME
------------------------------
PDB1
SQL>

PDBローカル管理者ユーザーPDBADMINに必要な権限があるかどうか確認します。

ここでは、以下の2つのテーブルを確認していきます。

  • SYS.DBA_ROLE_PRIVS – データベース内のすべてのユーザーおよびロールに付与されたロールを示す
  • SYS.DBA_SYS_PRIVS – ユーザーおよびロールに付与されたシステム権限を示す

まずはSYS.DBA_ROLE_PRIVSを確認します。

SQL> SELECT GRANTEE, GRANTED_ROLE, ADMIN_OPTION
  2  FROM SYS.DBA_ROLE_PRIVS
  3  WHERE GRANTEE = 'PDBADMIN'
  4  /

GRANTEE  GRANTED_ROLE ADM
-------- ------------ ---
PDBADMIN PDB_DBA      YES

SQL> 

PDB_DBAというロールを付与されていることがわかります。

次にSYS.DBA_SYS_PRIVSも確認しておきましょう。

SQL> select GRANTEE, PRIVILEGE, ADMIN_OPTION FROM SYS.DBA_SYS_PRIVS where GRANTEE = 'PDBADMIN'
  2  /

no rows selected

SQL> 

特に権限は付与されていません。

では、PDBADMINに与えられていたPDB_DBAロールについても確認していきます。

まずは、SYS.DBA_ROLE_PRIVSを確認します。

SQL> SELECT GRANTEE, GRANTED_ROLE, ADMIN_OPTION
  2  FROM SYS.DBA_ROLE_PRIVS
  3  WHERE GRANTEE = 'PDB_DBA'
  4  /

GRANTEE GRANTED_ROLE ADM
------- ------------ ---
PDB_DBA CONNECT      NO

SQL> 

CONNECTロールが付与されているだけでした。

次にSYS.DBA_SYS_PRIVSを確認します。

SQL> SELECT GRANTEE, PRIVILEGE, ADMIN_OPTION
  2  FROM SYS.DBA_SYS_PRIVS
  3  WHERE GRANTEE = 'PDB_DBA'
  4  /

GRANTEE PRIVILEGE                                ADM
------- ---------------------------------------- ---
PDB_DBA CREATE PLUGGABLE DATABASE                NO
PDB_DBA CREATE SESSION                           NO

SQL> 

CREATE PLUGGABLE DATABASECREATE SESSIONが付与されているだけで、DBA関連の権限は付与されていないことがわかります。

PDB_DBAロールにDBAロールを付与する

PDBローカル管理者ユーザーでローカルユーザーを作成できるようにするために、PDBローカル管理者ユーザーに付与されていたPDB_DBAロールにDBAロールを付与することにします。

SQL> GRANT DBA TO PDB_DBA;

Grant succeeded.

SQL> 

PDB_DBAロールにDBAロールが付与されているはずなので、確認しておきましょう。

SQL> SELECT GRANTEE, GRANTED_ROLE, ADMIN_OPTION
  2  FROM SYS.DBA_ROLE_PRIVS
  3  WHERE GRANTEE = 'PDB_DBA'
  4  /

GRANTEE GRANTED_ROLE ADM
------- ------------ ---
PDB_DBA DBA          NO
PDB_DBA CONNECT      NO

もともと付与されていたCONNECTロールに加え、DBAロールが付与されていることを確認できました。

これでPDBローカル管理者ユーザーPDBADMINでローカルユーザーの作成ができるようになったので、一度ログアウトしましょう。

SQL> exit
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

ローカルユーザーを作成する

今度はPDBADMINユーザーでPDB1へログインします。

$ sqlplus pdbadmin/oracle@pdb1

SQL*Plus: Release 19.0.0.0.0 - Production on Sat Mar 19 15:09:27 2022
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.

Last Successful login time: Sat Mar 19 2022 13:56:08 +00:00

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> 

くどいようですが、念のためPDB1に接続していることを確認します。

SQL> show con_name

CON_NAME
------------------------------
PDB1
SQL> 

テーブルスペースの確認

ローカルユーザーに割り当てるテーブルスペースを作成するべきかどうかを判断するために、テーブルスペースを確認します。

SQL> SELECT TABLESPACE_NAME, BLOCK_SIZE, INITIAL_EXTENT, MAX_EXTENTS, MAX_SIZE, STATUS, CONTENTS
  2  FROM SYS.DBA_TABLESPACES
  3  /

TABLESPACE_NAME BLOCK_SIZE INITIAL_EXTENT MAX_EXTENTS   MAX_SIZE STATUS CONTENTS
--------------- ---------- -------------- ----------- ---------- ------ ---------------------
SYSTEM                8192          65536  2147483645 2147483645 ONLINE PERMANENT
SYSAUX                8192          65536  2147483645 2147483645 ONLINE PERMANENT
UNDOTBS1              8192          65536  2147483645 2147483645 ONLINE UNDO
TEMP                  8192        1048576             2147483645 ONLINE TEMPORARY
USERS                 8192          65536  2147483645 2147483645 ONLINE PERMANENT


SQL> SELECT FILE_NAME, TABLESPACE_NAME, BYTES, BLOCKS, STATUS
  2  FROM SYS.DBA_DATA_FILES 
  3  /

FILE_NAME                                      TABLESPACE_NAME      BYTES     BLOCKS STATUS
---------------------------------------------- --------------- ---------- ---------- ---------
/opt/oracle/oradata/ORCLCDB/PDB1/undotbs01.dbf UNDOTBS1         104857600      12800 AVAILABLE
/opt/oracle/oradata/ORCLCDB/PDB1/sysaux01.dbf  SYSAUX           367001600      44800 AVAILABLE
/opt/oracle/oradata/ORCLCDB/PDB1/system01.dbf  SYSTEM           283115520      34560 AVAILABLE
/opt/oracle/oradata/ORCLCDB/PDB1/users01.dbf   USERS              5242880        640 AVAILABLE


SQL> 

デフォルトに使用したいUSERSテーブルスペース、テンポラリに使用したいTEMPテーブルスペースがすでに存在しているため、テーブルスペースは作成せず進めます。

ローカルユーザーを作成する

では、ローカルユーザーuser01を作成します。テーブルスペースは先ほど確認したUSERSテーブルスペースとTEMPテーブルスペースを使用します。

SQL> CREATE USER user01
  2  IDENTIFIED BY password
  3  DEFAULT TABLESPACE USERS
  4  QUOTA UNLIMITED ON USERS
  5  TEMPORARY TABLESPACE TEMP
  6  /

User created.

SQL> 

ローカルユーザーに権限を付与する

ユーザーを作成しただけでは何もできないユーザーになっているため、必要な権限を付与します。ここでは以下の3つを付与します。

  • RESOURCEロール – テーブル等のオブジェクト作成を可能にするロール
  • CREATE SESSION権限 – データベースに接続するために必要な権限
  • UNLIMITED TABLESPACE権限 – テーブルスペースを制限なしで使用できる権限
SQL> GRANT RESOURCE TO user01
  2  /

Grant succeeded.

SQL> GRANT CREATE SESSION TO user01
  2  /

Grant succeeded.

SQL> GRANT UNLIMITED TABLESPACE TO user01
  2  /

Grant succeeded.

SQL>

ロール、権限が付与されているか確認します。

SQL> SELECT GRANTEE, GRANTED_ROLE, ADMIN_OPTION
  2  FROM SYS.DBA_ROLE_PRIVS
  3  WHERE GRANTEE = 'USER01' 
  4  /

GRANTEE GRANTED_ROLE ADM
------- ------------ ---
USER01  RESOURCE     NO


SQL> SELECT GRANTEE, PRIVILEGE, ADMIN_OPTION
  2  FROM SYS.DBA_SYS_PRIVS
  3  WHERE GRANTEE = 'USER01'
  4  /

GRANTE PRIVILEGE                                ADM
------ ---------------------------------------- ---
USER01 UNLIMITED TABLESPACE                     NO
USER01 CREATE SESSION                           NO


SQL> 

意図したとおりに設定できていることが確認できました。

動作確認を行う

user01ユーザーが使用可能か確認するために、一度切断します。

SQL> exit
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

user01ユーザーでログインしてみます。

$ sqlplus user01/password@PDB1

SQL*Plus: Release 19.0.0.0.0 - Production on Sat Mar 19 15:28:15 2022
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.

Last Successful login time: Sat Mar 19 2022 15:27:20 +00:00

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> 

問題なく接続できていることを確認できました。

次にテーブルを作成し、データを追加、検索をしてみましょう。

SQL> CREATE TABLE emp
  2  (
  3    empno   VARCHAR2(10) NOT NULL,
  4    empname VARCHAR2(50),
  5    gender  NUMBER(1, 0)
  6  )
  7  /

Table created.

SQL> INSERT INTO emp VALUES ('ABC', 'DEF', '1')
  2  /

1 row created.

SQL> SELECT * FROM emp 
  2  /

EMPNO      EMPNAME                                                GENDER
---------- -------------------------------------------------- ----------
ABC        DEF                                                         1

SQL>

動作確認に使用したテーブルは不要なため、削除しておきます。

SQL> DROP TABLE emp 
  2  /

以上でローカルユーザーの作成が完了しました。

参考文献

sudoなしでdockerコマンドを実行できるようにする(dockerグループへユーザーを追加)

dockerコマンドを実行するときにsudoをつけずに実行できるようにする方法について解説します。

一般ユーザーがsudoなしで実行できるのは好ましい設定ではありません。本設定はローカル環境での利用にとどめ、ほかの人と共有して使用するサーバーや本番環境では、誤ってコンテナを停止してしまうなどの事故を防ぐためsudoを使用して操作することを推奨します。

ユーザーをdockerグループに追加する

手順自体はとてもシンプルですが、一つずつ確認していきます。

dockerグループの確認

まずはdockerグループがあるか確認します。

$ cat /etc/group | grep docker                                                                                                                                                           
docker:x:957:

Dockerのインストール方法にもよりますが、たいていはdockerグループが存在しています。

dockerグループが存在しない場合(コマンドを実行しても何も表示されない場合)は、以下のコマンドを実行してdockerグループを作成してください。

$ sudo groupadd docker

ユーザーをdockerグループに追加する

gpasswdコマンドを使ってdockerコマンドを使用したいユーザーをdockerグループに追加します。現在のユーザーを追加したい場合は以下のように実行します。

$ sudo gpasswd -a $USER docker                                                                                                                                                         
[sudo] password for xxx: 
Adding user xxx to group docker

現在のユーザー以外を追加したい場合は、$USERの部分を対象のユーザーに置き換えてください。

dockerデーモンを再起動する(dockerグループを作成した場合のみ)

dockerグループを作成した場合は、dockerデーモンの再起動が必要な場合があります。

systemctlを使用している場合は、以下のコマンドを実行します。

$ sudo systemctl restart docker                                                                                                                                                         
[sudo] password for xxx: 

ローカル環境で再起動しても問題ないのであれば、再起動していただいても構いません。

ログアウトして再度ログインする

前の手順で再起動している方はそのままログインしてください。それ以外の場合は一度ログアウトしてから、再度ログインしてください。

以上で、sudoなしでdockerコマンド(docker-composeコマンドも)が実行できるようになります。

なぜPermission deniedになるのか

そもそも、なぜdockerコマンドをsudoなしで実行するとPermission deniedになるかというと、dockerデーモンがUnixソケットを使用しており、dockerデーモンがrootユーザーで実行しているためです。

$ ls -l /var/run/docker.sock
srw-rw----  1 root    docker     0 Mar 19 09:51 docker.sock

実際に/var/run/docker.sockを見てみると、rootユーザーが所有者になっていることがわかります。

このことから、dockerデーモンと通信するdockerコマンドの実行には、docker.sockを読み取ることのできるrootユーザーまたはrootユーザー相当の権限が必要なため、sudoを使用します。

一方で、グループはdockerになっており、同様に読み取り権限があるため、ユーザーをdockerグループに追加することで、sudoを使用したときと同様にdockerコマンドが使用できるようになるという仕組みです。

ISOファイルをUSBフラッシュドライブ(USBメモリ)に書き込む(Rufus)

最近では、CD/DVDドライブが搭載されていないPCが多いため、LinuxのインストールなどではUSBフラッシュドライブ(以降はUSBメモリと表記)を使うことが一般的です。

本記事では、WindowsでISOファイルをUSBメモリに書き込むRufusというツールの使い方について解説します。

Rufusのダウンロード

まずは、公式サイトへアクセスします。

下のほうへスクロールしていくと、ダウンロードというセクションが見つかります。ここにある「Rufus x.xx」(執筆時点では「Rufus 3.18」)というリンクをクリックしてダウンロードしてください。

使用方法

ダウンロードしたrufus-x.xx.exeを起動すると、初回は以下のようなダイアログが表示される場合があります。

お好きなほうを選択してください。

ダイアログが閉じると、Rufusが起動します。

デバイスやボリュームラベルの表示内容はご使用のUSBメモリによって異なりますが、特に気にする必要はありません。
私は前回Linux Mint 20.3をインストールしたUSBメモリを使用しているため、このような表示になっています。

使用方法について行うことは多くなく、以下の3点を押さえておけば問題ありません。

  1. USBメモリを挿す
  2. ISOファイルを選択する
  3. 「スタート」ボタンをクリック(そして待つ)

まずは、USBメモリを挿しておいてください。デバイス欄にそのUSBの情報が表示されます。USBメモリを挿していない場合やうまく認識していない場合はデバイス欄は空欄になります。

USBメモリが認識されたら、次にISOファイルを選択します。ブートの種類欄の右の「選択」ボタンをクリックしてファイル選択ダイアログを表示します。

事前にダウンロードしておいたISOファイルを選択して、「開く」ボタンをクリックしてください。

USBメモリに書き込む準備ができました。「スタート」ボタンをクリックしてください。

いくつかダイアログが表示される場合があります。

ISOHybrid イメージの検出

ISO イメージモードで書き込む(推奨)」を選択したままで、「OK」ボタンをクリックしてください。

ダウンロードが必要です

「はい」ボタンをクリックしてください。

警告

すでにUSBメモリにデータがある場合に表示されます。使用しているUSBメモリが間違っていないことが確認できているのであれば「OK」ボタンをクリックしてください。

USBメモリへの書き込みが始まると、プログレスバーが増えていきます。

プログレスバーが100%になると、「スタート」ボタンがクリックできるようになります。

完了を通知するダイアログは示されないため、デバイス欄のUSBメモリの名前が変更されていること、やプログレスバーが100%で「準備完了」になっていることを確認してください。

asdfでよく使うコマンド集(アップデート、プラグイン、バージョン)

asdfの中でもよく使う、アップデート関連、プラグイン関連、バージョン関連のコマンドについて解説します。

アップデート関連

プラグイン自体のアップデートや追加したプラグインのアップデートについて解説します。

asdf自体のアップデート

それほど頻繁に実施する必要はりませんが、asdf自体をアップデートする場合は、以下のコマンドを実行します。

asdf update

すべてのプラグインのアップデート

特段理由がなければすべてのプラグインをアップデートする方が楽です。すでに追加済みのプラグインをすべてアップデートするときは、以下のコマンドを実行します。

asdf plugin-update --all

特定のプラグインのみをアップデート

たくさんのプラグインを追加していて全部アップデートするのは時間がかかる、バージョンをあげたくないプラグインがある、など何かしらの理由があって特定のプラグインのみをアップデートしたいときは、以下のコマンドを実行します。

asdf plugin-update <プラグイン名>

<プラグイン名>には、アップデートしたいプラグインを指定します。

プラグイン関連

プラグインの表示、追加、削除など基本的な操作について解説します。

プラグインの一覧表示

プラグインを一覧表示するときは、以下のコマンドを実行します。

asdf plugin list all

大量に表示されますので、Grepで対象を絞り込む方がよいでしょう。

$ asdf plugin list all | grep node                                                                                                                                                                                
nodejs                       *https://github.com/asdf-vm/asdf-nodejs.git

上記の例では、Node.jsのプラグイン名を調べるためににnodeでGrepし、nodejsであることが分かりました。

現在インストール中のプラグインの一覧表示

すでにインストール済みのプラグインをしたいときは、以下のコマンドを実行します。

asdf plugin list

プラグインの追加

プラグインを追加するときは、以下のコマンドを実行します。

asdf plugin add <プラグイン名>

<プラグイン名>のところは、追加したいプラグインの名前を指定します。

プラグインの削除

プラグインを削除するときは、以下のコマンドを実行します。

asdf plugin remove <プラグイン名>

<プラグイン名>のところは、削除したいプラグインの名前を指定します。

バージョン関連

バージョンに関する操作について解説します。

使用可能なバージョンの一覧表示

特定のプラグインの使用可能なバージョンを一覧表示したいときは、以下のコマンドを実行します。

asdf list all <プラグイン名>

こちらもGrepを併用することでインストールしたいバージョンを特定するのがよいでしょう。

asdf list all nodejs | grep ^11.

上記のでは、nodejsパッケージのうち、11系だけをGrepで絞り込んでいます。

インストール済みのバージョンを一覧表示

すでにインストール済みのバージョンを一覧表示したいときは、以下のコマンドを実行します。

asdf list <プラグイン名>

バージョンをインストールする

指定したバージョンをインストールするときは、以下のコマンドを実行します。

asdf install <プラグイン名> <バージョン>

<プラグイン名>はインストールしたいプラグインの名前、<バージョン>はインストールしたいバージョンを指定します。

バージョンをアンインストールする

指定したバージョンをアンインストールするときは、以下のコマンドを実行します。

asdf uninstall <プラグイン名> <バージョン>

<プラグイン名>はアンインストールしたいプラグインの名前、<バージョン>はアンインストールしたいバージョンを指定します。

バージョンの設定

asdfでは、globallocalshellの3つの設定範囲があります。使用目的によって適切な設定範囲を選択することで、効率よくバージョン管理を行うことができます。

globalバージョンの設定

globalバージョンは、特に指定がない場合に使用されるバージョンです。globalバージョンを設定するときは、以下のコマンドを実行します。

asdf global <プラグイン名> <バージョン>

<プラグイン名>はglobalバージョンを設定したいプラグインの名前、<バージョン>はglobalバージョンに設定したいバージョンを指定します。

globalバージョンは、システム全体で使用するバージョンを設定するとよいでしょう。言い方を変えると、特段理由がない場合に使用するバージョンであるとも言えます。例えば、メインストリームのバージョンやLTSのバージョンを設定しておく運用方法が適切です。

localバージョンの設定

特定のフォルダ(ディレクトリ)内でのみ有効なバージョンです。globalバージョンで使用しているバージョンとは異なるバージョンを使いたい場合に使用するとよいでしょう。

localバージョンを設定するときは、以下のコマンドを実行します。

asdf local <プラグイン名> <バージョン>

現在のフォルダ(ディレクトリ)およびそのサブフォルダ(ディレクトリ)ではlocalバージョンが有効になります。このとき、.tool-versionsが作成され、使用するプラグインとバージョンが記録されます。

localバージョンは、プロジェクトで使用するバージョンを指定するために使用するとよいでしょう。
例えば、普段はPython 3.9.xを使用していますが、今携わっているプロジェクトでは、Python 3.7.xでないとビルドができないとしましょう。
この場合、globalバージョンは3.9.xですが、プロジェクトのフォルダ(ディレクトリ)内ではPython 3.7.xをlocalバージョンに指定しておくことで、このプロジェクト内だけは3.7.xを使用することができます。
もし、複数の保守プロジェクトを抱えている場合であれば、この恩恵はとても大きいものになります。

shellバージョンの設定

シェル内でのみ有効なバージョンです。使用頻度は高くありませんが、使用するコマンドが特定のバージョンを要求する場合などに重宝します。

shellバージョンを設定するときは、以下のコマンドを実行します。

asdf shell <プラグイン名> <バージョン>

これは現在のシェルの設定が変わるわけではなく、新にシェルを起動し、そこでのバージョンが設定したバージョンになります。そのため、使用を終了する場合は、exitコマンドで抜けることができます。

shellバージョンは、特定のコマンドやツールを実行する際に、特定のバージョンまたは特定のバージョン以下でないと実行できない、といった場合に使用するとよいでしょう。
例えば、プロジェクトでは、Node.js 16.xを使用しています。リリース用のツールもNode.jsで書かれていますが、古いツールなためNode.js 11.xでないと動作しません。
こういった場合には、globalバージョンまたはlocalバージョンは16.xを設定し、ツールを実行するときだけ、shellバージョンに11.xを設定してコマンドを実行する運用にする方が、バージョンアップ対応を行うよりもコストメリットがあります。

Gitを使い始めるときに行う設定(git config)

Gitをインストールした後など、使い始めるときに行う2つの設定について解説します。

ユーザー名を設定する

使い始める前に行う設定の1つ目はユーザー名の設定です。

git config --global user.name "Taro Yamada"

user.nameユーザー名を表します。一般的には本名をローマ字で書くのが一般的ですが、ハンドル名やニックネーム等を使用しても構いません。

仕事で使う場合は、組織やプロジェクトでのルールに従ってください。

氏名をユーザー名に設定する場合、姓と名の間に半角スペースを含むため、ユーザー名全体を「”」(ダブルクォーテーション)で囲みます。スペースを含まない場合は「”」(ダブルクォーテーション)で囲む必要はありません。

メールアドレスを設定する

使い始める前に行う設定のもう一つは、メールアドレスの設定です。

git config --global user.email taro.yamada@example.com

user.emailメールアドレスを表します。

使用可能なメールを使用することが強く推奨されるため、個人開発の場合は個人のメールアドレス、仕事での開発の場合は組織で使用されているメールアドレスを使用してください。

メールアドレスにはスペースを含むことがないので「”」(ダブルクォーテーション)は必要ありません。

設定を確認する

現在の設定を確認するには、-lオプションを使います。

前述の設定を行ったあとに、設定を確認すると以下のような結果になります。

$ git config --global -l

user.name=Taro Yamada
user.email=taro.yamada@example.com

ユーザー名とメールアドレスは何に使うの?

設定したユーザー名とメールアドレスはどこに使われるのでしょうか?

設定したユーザー名とメールアドレスは、コミットログのAuthorに使用されます。
前述の設定を行ったうえでファイルをコミットして、ログでコミットログを確認すると以下のようになります。

$ git log       
commit daa1b044d5794411dd25e9f404a4f96a0b4d1006 (HEAD -> main)
Author: Taro Yamada 
Date:   Sat Mar 12 20:45:39 2022 +0900

    add test.txt

Author欄に先ほど設定したユーザー名とメールアドレスが設定されていることが分かります。

プロジェクト固有の設定を行いたい場合は?

すでに説明した設定はグローバル設定(--global)となっています。

例えば、

在宅勤務で自宅のPCをしており、普段は個人で開発していますが、仕事でも使うことになりました。
個人で開発する際のユーザー名とメールアドレスはグローバル設定として登録済みです。仕事では会社のメールアドレスを使う必要があります。

この場合、ローカル設定を使うことで解決できます。

まずは現在のグローバル設定を確認します。

$ git config --global -l

user.name=Taro Yamada
user.email=taro.yamada@example.com

次に仕事で使うプロジェクト(ここでは「user_service」)に移動して、再度設定を確認します。

$ cd user_service
$ git config --global -l

user.name=Taro Yamada
user.email=taro.yamada@example.com

当然ですが、設定は変わりません。
ここではローカル設定(--local)を行います。

まずは設定を行います。

$ git config --local user.name t-yamada
$ git config --local user.email t-yamada@kaisha.com

先ほどとの違いは、--global--localになっただけです。

では、設定を確認してみましょう。設定の確認も同様に--localオプションを使用します。

$ git config --local -l
core.repositoryformatversion=0
core.filemode=false
core.bare=false
core.logallrefupdates=true
core.symlinks=false
core.ignorecase=true
user.name=t-yamada
user.email=t-yamada@kaisha.com

少し余計な設定が出力されていますが、一番下にuser.nameuser.emailが出力されており、設定値は--localオプションを使用して設定したものになっています。

では適当なファイルをコミットして、コミットログを確認してみます。

$ touch test.txt
$ git add test.txt
$ git commit -m 'add test.txt'
[main (root-commit) 11eecab] add test.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt
$ git log 
commit 11eecab9335ca6e43e4efc6c2a43f37fb7be41b3 (HEAD -> main)
Author: t-yamada 
Date:   Sat Mar 12 21:55:04 2022 +0900

    add test.txt

ファイルの追加やコミットのオプションは特に変えていませんが、確かに--localで設定したユーザー名、メールアドレスで記録されています。

このように複数の環境を使い分ける場合はローカル設定を活用してください。

Gitリポジトリの初期化を行う(git init)

Gitでファイル管理を始めるために初期化を行う方法を解説します。

Gitリポジトリの初期化を行う

では、フォルダ/ディレクトリ(以降はフォルダと表記)を作成し、そこに空のリポジトリを作成する手順を見てみましょう。

まずは、フォルダを作成し、その中に移動します。

$ mkdir test
$ cd test
$ ls -a
./  ../

隠しファイルも含めて表示し、空のフォルダであることがわかります。

次にgit initコマンドを実行します。

$ git init
Initialized empty Git repository in /home/taro/test/.git/

空のGitリポジトリを初期化した旨のメッセージが出力されています。では、再度フォルダの中がどうなっているか確認してみます。

$ ls -a
./  ../  .git/

先ほどまではなかった.gitという隠しフォルダが作成されていることがわかります。

これでGitリポジトリの初期化が完了し、gitコマンドが使えるようになります。

オプションはあるが使用することはほとんどない

実はgit initには、オプションがあります。

ですが、オプションを使用することはほとんどないと言っていいので、気にする必要はありません。実用上は、

Gitリポジトリの初期化を行いたいフォルダへ移動して、git initを実行する

とだけ理解しておけば充分です。

モバイルバージョンを終了