MATLAB table入門:データ処理に役立つ使い方を解説

MATLAB table入門:データ処理に役立つ使い方を徹底解説

はじめに:なぜMATLABでtableを使うべきなのか?

科学技術計算やデータ解析において、MATLABは非常に強力なツールです。数値計算、アルゴリズム開発、モデリング、シミュレーション、データ解析、視覚化など、幅広い用途で利用されています。特にデータ解析の分野では、様々な形式のデータを効率的に扱い、意味のある情報を抽出することが求められます。

これまでMATLABでデータを扱う場合、主に以下のデータ構造が利用されてきました。

  • 配列 (Arrays): 数値データ(double, single, int, logicalなど)を格納するのに最適です。計算処理は高速ですが、同じ型のデータしか格納できません。
  • 構造体 (Structs): 異なる型のデータをフィールド名で管理できます。レコード指向のデータ構造であり、個々の観測データ(例:ある被験者の名前、年齢、身長、体重)をまとめて扱うのに便利です。しかし、列方向の操作(例:全被験者の身長の平均を計算)はやや煩雑になることがあります。
  • セル配列 (Cell Arrays): 異なる型のデータを柔軟に格納できます。非常に柔軟性が高い反面、データの構造が明確になりにくく、特定のデータを取り出して処理する際にセルごとの処理(cellfunなど)が必要になる場合があり、コードが複雑になりがちです。

これらのデータ構造はそれぞれに利点がありますが、現実世界のデータ、特に統計データや実験データは、数値データだけでなく、テキストデータ(文字列)、カテゴリカルデータ、日付・時間データなど、多様な型のデータが混在していることがよくあります。さらに、各列(変数)が何を意味するのか、各行(観測)が何を意味するのかが明確である必要があり、これらの情報(変数名、行名)とともにデータを管理できると、データ処理のコードは格段に分かりやすくなります。

このような背景から、MATLAB R2013b以降で導入されたのがtableクラスです。tableは、変数(列)ごとに異なるデータ型を持つことができ、各変数には明確な名前、各行にはオプションで行名をつけることができる、構造化されたデータ形式です。これは、RのデータフレームやPythonのpandas DataFrameに相当するもので、表形式のデータを扱う上で非常に強力な機能を提供します。

tableを利用することで、以下のようなメリットが得られます。

  • 可読性の向上: 変数名で行にアクセスできるため、コードが直感的で分かりやすくなります。
  • 柔軟なデータ型の混在: 数値、文字列、カテゴリカル、logical、日付・時間など、様々なデータ型の列を一つのテーブル内に保持できます。
  • 容易なデータ操作: 列の選択、行のフィルタリング、データの結合、集計といった一般的なデータ処理操作が、専用の関数や直感的な構文で簡単に行えます。
  • 欠損値の管理: NaNだけでなく、数値以外の型の欠損値を表現・処理しやすくなります。
  • 専門関数のサポート: 統計、機械学習、曲線フィッティングなど、多くのMATLABツールボックス関数がtable形式の入力をサポートしています。

この記事では、MATLABのtableについて、その基本的な使い方から、実際のデータ処理に役立つ応用的なテクニックまでを詳細に解説します。約5000語というボリュームで、初心者の方でもtableをマスターし、日々のデータ解析業務を効率化できるよう、具体的なコード例を豊富に含めて説明していきます。

1. MATLAB tableの基本

tableは、異なる型のデータを列(変数)として保持できる、二次元のラベル付きデータ構造です。各列は同じ行数を持つ必要があり、各行は一つの観測(またはレコード)を表します。

1.1. tableとは何か?

tableは「列指向」のデータ構造です。つまり、データは基本的に列ごとに管理されます。各列は「変数」と呼ばれ、独自のデータ型(double, string, categorical, datetimeなど)を持つことができます。各行にはオプションで「行名」を付けることができ、データの特定の観測を識別するのに役立ちます。

イメージとしては、スプレッドシートやデータベースのテーブルに非常に近いものです。

行名 変数1 (数値) 変数2 (文字列) 変数3 (論理値)
‘Obs1’ 1.2 “Apple” true
‘Obs2’ 3.4 “Banana” false
‘Obs3’ 5.6 “Cherry” true

1.2. tableの作成方法

tableを作成する方法はいくつかあります。

方法1:既存の変数からの作成 (table()関数)

複数のMATLAB変数(配列、セル配列、文字列配列など)を組み合わせてテーブルを作成するのが最も基本的な方法です。table()関数を使用し、引数として変数名と対応する変数値をペアで指定します。変数名は文字ベクトルまたは文字列スカラーで指定します。

“`matlab
% データの準備
ID = [101; 102; 103; 104];
Name = [“Alice”; “Bob”; “Charlie”; “David”];
Age = [25; 30; 22; 35];
IsStudent = [true; false; true; false];

% tableの作成
data = table(ID, Name, Age, IsStudent);

% tableを表示
disp(data);
“`

出力例:

ID Name Age IsStudent
__ ______ ___ _________
101 "Alice" 25 true
102 "Bob" 30 false
103 "Charlie" 22 true
104 "David" 35 false

このように、異なる型の変数が一つのテーブルに格納され、変数名も自動的に設定されます。table()関数に渡す変数名は、テーブルの変数名として使用されます。変数名を明示的に指定したい場合は、'VariableNames'オプションを使用します。

matlab
data = table(ID, Name, Age, IsStudent, 'VariableNames', {'PatientID', 'FullName', 'YearsOld', 'IsEnrolled'});
disp(data);

出力例:

PatientID FullName YearsOld IsEnrolled
_________ ________ ________ __________
101 "Alice" 25 true
102 "Bob" 30 false
103 "Charlie" 22 true
104 "David" 35 false

行名を指定したい場合は、'RowNames'オプションを使用します。行名は一意である必要があります。

matlab
rowNames = {'P1', 'P2', 'P3', 'P4'};
data = table(ID, Name, Age, IsStudent, 'RowNames', rowNames);
disp(data);

出力例:

ID Name Age IsStudent
__ ______ ___ _________
P1 101 "Alice" 25 true
P2 102 "Bob" 30 false
P3 103 "Charlie" 22 true
P4 104 "David" 35 false

方法2:ファイルからの読み込み (readtable()関数)

CSV, Excel,区切り文字付きテキストファイルなど、表形式のデータファイルを読み込んで直接tableを作成することができます。これは、外部データを取り込む際の最も一般的な方法です。

“`matlab
% 例として、以下の内容の ‘sample_data.csv’ ファイルがあるとします。
% ID,Name,Age,IsStudent
% 101,Alice,25,true
% 102,Bob,30,false
% 103,Charlie,22,true
% 104,David,35,false

% ファイルからtableを読み込み
dataFromFile = readtable(‘sample_data.csv’);

% tableを表示
disp(dataFromFile);
“`

readtable関数は、ファイルの形式を自動的に判別し、適切なパーサーを使用してデータを読み込みます。ヘッダー行を変数名として、各列のデータ型を推測してくれます。オプション引数を使って、区切り文字の指定、ヘッダー行の有無、特定の列だけを読み込む、特定の列のデータ型を指定する、欠損値の指定など、詳細な読み込み設定が可能です。

“`matlab
% タブ区切りファイルで、特定の列だけを読み込む例
% data = readtable(‘another_data.tsv’, ‘Delimiter’, ‘\t’, ‘SelectedVariableNames’, {‘Name’, ‘Score’});

% 欠損値を示す文字列を指定する例
% data = readtable(‘data_with_missing.csv’, ‘MissingValue’, ‘N/A’);
“`

方法3:空のtableの作成

最初に空のテーブルを作成しておき、後からデータを追加していく方法です。データのサイズが前もって分からない場合や、ループ処理でデータを収集する場合などに便利です。

“`matlab
% 空のtableを作成
emptyTable = table();
disp(emptyTable); % 0x0 table と表示されます

% 変数を定義して追加
IDs = []; % または zeros(0,1);
Names = string([]); % または cell(0,1);
Ages = [];

% 初期構造を持つ空のテーブルを作成(後から行を追加しやすい)
templateTable = table(‘Size’, [0, 3], ‘VariableTypes’, {‘double’, ‘string’, ‘double’}, ‘VariableNames’, {‘ID’, ‘Name’, ‘Age’});
disp(templateTable);

% 後で行を追加する方法は後述します。
“`

1.3. tableの構造

tableは、以下の要素で構成されます。

  • 変数 (Variables): 列のことです。各変数には名前があり、特定のデータ型を持ちます。table.Properties.VariableNamesプロパティで変数名のリストを取得できます。
  • 観測 (Observations): 行のことです。各観測はテーブルの1行に対応します。
  • 行名 (Row Names): 各行に付けることができるオプションの名前です。一意である必要があります。table.Properties.RowNamesプロパティで行名を取得できます。
  • プロパティ (Properties): テーブル全体に関する情報(変数名、行名、次元名など)を格納するメタデータです。T.Propertiesでアクセスできます。

“`matlab
disp(data);

% 変数名を取得
varNames = data.Properties.VariableNames;
disp(‘変数名:’);
disp(varNames);

% 行名を取得
rowNames = data.Properties.RowNames; % 行名を指定していない場合は空のセル配列 {}
disp(‘行名:’);
disp(rowNames);

% テーブルのサイズを取得
[numRows, numCols] = size(data);
disp([‘行数: ‘, num2str(numRows)]);
disp([‘列数: ‘, num2str(numCols)]);

% または height/widthプロパティでも取得可能
numRows = height(data);
numCols = width(data);
disp([‘行数 (height): ‘, num2str(numRows)]);
disp([‘列数 (width): ‘, num2str(numCols)]);
“`

出力例(行名を指定した場合):

“`
ID Name Age IsStudent
__ __ ___ _
P1 101 “Alice” 25 true
P2 102 “Bob” 30 false
P3 103 “Charlie” 22 true
P4 104 “David” 35 false

変数名:
{‘ID’, ‘Name’, ‘Age’, ‘IsStudent’}

行名:
{‘P1’, ‘P2’, ‘P3’, ‘P4’}

行数: 4
列数: 4
行数 (height): 4
列数 (width): 4
“`

2. tableデータのアクセスと抽出

tableから特定のデータを取り出す方法は複数あり、用途に応じて使い分けることが重要です。アクセス方法によって、返されるデータの型が変わるため注意が必要です。

2.1. アクセス方法の種類

tableのデータにアクセスするには、主に以下の3つの方法があります。

  1. 丸括弧 () によるインデックス付け: サブテーブルを返します。
  2. 波括弧 {} によるインデックス付け: セル配列のように、テーブル内のデータ本体を返します。複数のデータ型を持つ列を含む場合はセル配列、単一のデータ型を持つ列のみの場合はそのデータ型の配列になります。
  3. ドット . による変数名アクセス: 特定の変数(列)全体を、その変数本来のデータ型の配列として返します。

これらのインデックス付けは、行と列に対して独立に行うことができます。行は数値インデックスまたは行名、列は数値インデックスまたは変数名で指定できます。

matlab
% tableの準備 (行名あり)
ID = [101; 102; 103; 104];
Name = ["Alice"; "Bob"; "Charlie"; "David"];
Age = [25; 30; 22; 35];
IsStudent = [true; false; true; false];
rowNames = {'P1', 'P2', 'P3', 'P4'};
T = table(ID, Name, Age, IsStudent, 'RowNames', rowNames);
disp(T);

丸括弧 () によるアクセス(サブテーブルの抽出)

T(rows, cols) の形式で使用します。指定した行と列に対応する新しいテーブルを返します。

  • 行の指定:
    • 数値インデックス: 1, [1 3], 1:end
    • 論理インデックス: T.Age > 25 のような論理配列
    • 行名: 'P1', {'P1', 'P3'}
  • 列の指定:
    • 数値インデックス: 1, [1 3], 1:end
    • 変数名: 'Age', {'Name', 'Age'}
    • 論理インデックス: [true false true false] のような論理配列(列数と同じ長さ)

“`matlab
% 1行目と3行目のデータを抽出(数値インデックス)
subTable1 = T([1 3], :); % ‘:’ は全ての列を意味します
disp(‘サブテーブル (行インデックス):’);
disp(subTable1);

% Ageが25より大きい行を抽出(論理インデックス)
logicalIndex = T.Age > 25;
subTable2 = T(logicalIndex, :);
disp(‘サブテーブル (論理インデックス):’);
disp(subTable2);

% 行名 ‘P1’ と ‘P3’ のデータを抽出
subTable3 = T({‘P1’, ‘P3’}, :);
disp(‘サブテーブル (行名):’);
disp(subTable3);

% ‘Name’ 列と ‘Age’ 列を抽出(変数名)
subTable4 = T(:, {‘Name’, ‘Age’});
disp(‘サブテーブル (変数名):’);
disp(subTable4);

% 行名 ‘P2’ と ‘P4’ の ‘ID’ と ‘IsStudent’ 列を抽出
subTable5 = T({‘P2’, ‘P4’}, {‘ID’, ‘IsStudent’});
disp(‘サブテーブル (行名と変数名):’);
disp(subTable5);
“`

出力例:

“`
サブテーブル (行インデックス):
ID Name Age IsStudent
__ __ ___ _
P1 101 “Alice” 25 true
P3 103 “Charlie” 22 true

サブテーブル (論理インデックス):
ID Name Age IsStudent
__ __ ___ _
P2 102 “Bob” 30 false
P4 104 “David” 35 false

サブテーブル (行名):
ID Name Age IsStudent
__ __ ___ _
P1 101 “Alice” 25 true
P3 103 “Charlie” 22 true

サブテーブル (変数名):
Name Age
______ ___
P1 “Alice” 25
P2 “Bob” 30
P3 “Charlie” 22
P4 “David” 35

サブテーブル (行名と変数名):
ID IsStudent
__ ___
P2 102 false
P4 104 false
“`

波括弧 {} によるアクセス(データ本体の抽出)

T{rows, cols} の形式で使用します。指定した行と列に対応するデータを取り出します。

  • 抽出対象が1つのセルであれば、そのセル内の値そのもの(スカラー値、文字列など)が返されます。
  • 抽出対象が複数のセルであれば、それらを格納したセル配列が返されます。
  • 抽出対象が単一のデータ型を持つ複数のセル(例:数値列の複数行)であれば、そのデータ型の配列が返される場合もあります(MATLAB R2019b以降の挙動)。

“`matlab
% 2行目の ‘Name’ 列のデータを取り出す(単一セル)
nameBob = T{2, ‘Name’};
disp([‘2行目の名前 (単一セル): ‘, nameBob]);
disp([‘データ型: ‘, class(nameBob)]); % string

% 1行目から3行目の ‘Age’ 列のデータを取り出す(複数セル、同じ型)
ages = T{[1 2 3], ‘Age’};
disp(‘1-3行目の年齢 (複数セル、同じ型):’);
disp(ages);
disp([‘データ型: ‘, class(ages)]); % double

% 1行目から3行目の ‘Name’ と ‘Age’ 列のデータを取り出す(複数セル、異なる型)
nameAndAge = T{[1 2 3], {‘Name’, ‘Age’}};
disp(‘1-3行目の名前と年齢 (複数セル、異なる型):’);
disp(nameAndAge);
disp([‘データ型: ‘, class(nameAndAge)]); % cell
“`

出力例:

2行目の名前 (単一セル): Bob
データ型: string
1-3行目の年齢 (複数セル、同じ型):
25
30
22
データ型: double
1-3行目の名前と年齢 (複数セル、異なる型):
'Alice' [25]
'Bob' [30]
'Charlie' [22]
データ型: cell

{} は、テーブルの「中身」を取り出すイメージです。特に、単一のセルや、特定の列の複数要素を元のデータ型で取得したい場合に便利です。

ドット . によるアクセス(特定の変数全体)

T.VariableName の形式で使用します。指定した変数(列)全体を、その変数本来のデータ型の配列として返します。これは単一の列にしか使用できません。

“`matlab
% ‘Age’ 列全体を配列として取り出す
ageColumn = T.Age;
disp(‘Age 列全体:’);
disp(ageColumn);
disp([‘データ型: ‘, class(ageColumn)]); % double

% ‘Name’ 列全体を文字列配列として取り出す
nameColumn = T.Name;
disp(‘Name 列全体:’);
disp(nameColumn);
disp([‘データ型: ‘, class(nameColumn)]); % string
“`

出力例:

Age 列全体:
25
30
22
35
データ型: double
Name 列全体:
"Alice"
"Bob"
"Charlie"
"David"
データ型: string

T.VariableName は、特定の列全体に対して操作を行いたい場合に最も直感的でよく使われる方法です。例えば、列の平均を計算する (mean(T.Age))、列の値を全て大文字に変換する (upper(T.Name)) といった操作が容易になります。

2.2. まとめ:アクセス方法の使い分け

  • T(rows, cols): サブテーブルが必要な場合。元のテーブル構造を維持したまま一部を取りたい。
  • T{rows, cols}: テーブル内のデータ本体が必要な場合。特に単一のセルや、異なる型の複数要素を取り出したい。
  • T.VariableName: 特定の列全体を、その列本来のデータ型の配列として取得したい場合。最もよく使う方法の一つ。

2.3. 論理インデックスによる抽出

特定の条件を満たす行を抽出するのは、データ処理で非常に頻繁に行う操作です。MATLABのtableでは、論理配列を使って直感的に行をフィルタリングできます。

例えば、「年齢が30歳以上の人」または「学生である人」を抽出したい場合:

“`matlab
% 条件を作成(論理配列)
isAge30OrOlder = T.Age >= 30;
isStudent = T.IsStudent;

% 論理和 (OR) で条件を組み合わせる
combinedCondition = isAge30OrOlder | isStudent;

% 論理インデックスを使って行を抽出
filteredTable = T(combinedCondition, :);
disp(‘年齢 >= 30 または 学生 のデータ:’);
disp(filteredTable);

% 論理積 (AND) で条件を組み合わせる例
% isAge25OrOlder = T.Age >= 25;
% isNotStudent = ~T.IsStudent;
% filteredTable2 = T(isAge25OrOlder & isNotStudent, :); % 年齢 >= 25 かつ 学生ではない 人
“`

出力例:

年齢 >= 30 または 学生 のデータ:
ID Name Age IsStudent
__ ______ ___ _________
P1 101 "Alice" 25 true
P2 102 "Bob" 30 false
P3 103 "Charlie" 22 true
P4 104 "David" 35 false

この例では、Alice (学生), Bob (30歳), Charlie (学生), David (35歳) の全てが条件を満たしています。

論理インデックスは、特定の列の値に条件を適用して、その条件を満たす行全体を選択する強力な方法です。

3. tableデータの操作と変更

既存のテーブルのデータを変更したり、新しいデータを追加したりすることも簡単に行えます。

3.1. データの追加

列(変数)の追加

新しい列をテーブルに追加するには、ドット構文を使用するのが最も簡単です。新しい変数名を使って値を代入します。代入するデータの行数は既存のテーブルの行数と一致している必要があります。

“`matlab
% 新しいデータの準備
Score = [85; 92; 78; 95];
City = [“Tokyo”; “Osaka”; “Sapporo”; “Fukuoka”];

% 新しい列を追加
T.Score = Score;
T.City = City;

disp(‘Score と City 列を追加したテーブル:’);
disp(T);
“`

出力例:

ID Name Age IsStudent Score City
__ ______ ___ _________ _____ _________
P1 101 "Alice" 25 true 85 "Tokyo"
P2 102 "Bob" 30 false 92 "Osaka"
P3 103 "Charlie" 22 true 78 "Sapporo"
P4 104 "David" 35 false 95 "Fukuoka"

新しい列を追加する別の方法として、水平方向の結合(horzcat)を使うこともできますが、ドット構文の方が直感的でよく使われます。

行の追加

新しい行をテーブルに追加するには、垂直方向の結合(vertcat)を使用するのが最も一般的です。同じ変数名とデータ型を持つ別のテーブル(または1行のテーブル)を結合します。

“`matlab
% 追加する新しい行のデータ
newID = 105;
newName = “Eve”;
newAge = 28;
newIsStudent = true;
newScore = 88;
newCity = “Nagoya”;

% 新しい行を1行のテーブルとして作成
newRow = table(newID, newName, newAge, newIsStudent, newScore, newCity, …
‘VariableNames’, {‘ID’, ‘Name’, ‘Age’, ‘IsStudent’, ‘Score’, ‘City’});
% 行名を追加する場合(省略可能)
newRow.Properties.RowNames = {‘P5’};

% 既存のテーブルと結合
T = vertcat(T, newRow);

disp(‘新しい行を追加したテーブル:’);
disp(T);
“`

出力例:

ID Name Age IsStudent Score City
__ ______ ___ _________ _____ _________
P1 101 "Alice" 25 true 85 "Tokyo"
P2 102 "Bob" 30 false 92 "Osaka"
P3 103 "Charlie" 22 true 78 "Sapporo"
P4 104 "David" 35 false 95 "Fukuoka"
P5 105 "Eve" 28 true 88 "Nagoya"

vertcat を使う場合、結合する両方のテーブルで変数名とデータ型が一致している必要があります。順番が違っても、変数名が一致していれば正しく結合されます。

空のテーブルにループでデータを追加していく場合も vertcat が便利です。

“`matlab
% 空のテーブルをテンプレートとして作成
templateTable = table(‘Size’, [0, 3], ‘VariableTypes’, {‘double’, ‘string’, ‘double’}, …
‘VariableNames’, {‘ID’, ‘Name’, ‘Age’});

% ループでデータを生成し、テーブルに追加
for i = 1:3
currentID = 200 + i;
currentName = sprintf(‘User%d’, i);
currentAge = 20 + i;

% 現在のデータを1行のテーブルとして作成
currentRow = table(currentID, string(currentName), currentAge, ...
                   'VariableNames', {'ID', 'Name', 'Age'});

% テーブルに結合
templateTable = vertcat(templateTable, currentRow);

end

disp(‘ループでデータ追加したテーブル:’);
disp(templateTable);
“`

出力例:

ID Name Age
___ ________ ___
201 "User1" 21
202 "User2" 22
203 "User3" 23

3.2. データの削除

列(変数)の削除

特定の列を削除するには、ドット構文または丸括弧構文で削除したい列を選択し、空の配列 [] を代入します。

“`matlab
disp(‘元のテーブル:’);
disp(T); % ScoreとCityがあるテーブル

% ‘City’ 列を削除 (ドット構文)
T.City = [];
disp(‘”City” 列を削除したテーブル:’);
disp(T);

% ‘Score’ 列を削除 (丸括弧構文)
T(:, ‘Score’) = [];
disp(‘”Score” 列を削除したテーブル:’);
disp(T);
“`

出力例(削除後のテーブルはID, Name, Age, IsStudent 列のみになります):

ID Name Age IsStudent
__ ______ ___ _________
P1 101 "Alice" 25 true
P2 102 "Bob" 30 false
P3 103 "Charlie" 22 true
P4 104 "David" 35 false
P5 105 "Eve" 28 true

行の削除

特定の行を削除するには、丸括弧構文で削除したい行を選択し、空の配列 [] を代入します。

“`matlab
disp(‘元のテーブル:’);
disp(T); % 5行あるテーブル

% 2行目を削除 (数値インデックス)
T(2, 🙂 = [];
disp(‘2行目を削除したテーブル:’);
disp(T);

% 行名 ‘P5’ の行を削除 (行名)
T(‘P5’, 🙂 = [];
disp(‘行名 “P5” の行を削除したテーブル:’);
disp(T);

% Ageが25未満の行を削除 (論理インデックス)
logicalIndexToDelete = T.Age < 25;
T(logicalIndexToDelete, 🙂 = [];
disp(‘Age < 25 の行を削除したテーブル:’);
disp(T);
“`

出力例:
(削除の順序によって結果は変わりますが、最終的に Age < 25 の行が消えます)

Age < 25 の行を削除したテーブル:
ID Name Age IsStudent
__ ______ ___ _________
P2 102 "Bob" 30 false
P4 104 "David" 35 false

3.3. データの更新

特定のセル、特定の列、または特定の条件を満たすセルの値を変更することができます。

特定のセルの値の変更

波括弧 {} を使用して、変更したいセルを指定し、新しい値を代入します。代入する値の型は、その列のデータ型と互換性がある必要があります。

“`matlab
disp(‘元のテーブル:’);
disp(T); % Age 30, 35 のテーブル

% 2行目の Age を 31 に変更 (数値インデックスと変数名)
T{2, ‘Age’} = 31;
disp(‘2行目の Age を変更したテーブル:’);
disp(T);

% 行名 ‘P4’ の Name を “Dave” に変更 (行名と変数名)
T{‘P4’, ‘Name’} = “Dave”;
disp(‘行名 “P4” の Name を変更したテーブル:’);
disp(T);
“`

出力例:

“`
元のテーブル:
ID Name Age IsStudent
__ __ ___ _
P2 102 “Bob” 30 false
P4 104 “David” 35 false

2行目の Age を変更したテーブル:
ID Name Age IsStudent
__ __ ___ _
P2 102 “Bob” 31 false
P4 104 “David” 35 false

行名 “P4” の Name を変更したテーブル:
ID Name Age IsStudent
__ __ ___ _
P2 102 “Bob” 31 false
P4 104 “Dave” 35 false
“`

特定の列全体の変更

ドット構文または丸括弧構文で列全体を選択し、新しい配列を代入します。代入する配列の行数は、テーブルの行数と一致している必要があります。

“`matlab
% 元のテーブルに戻す(例として)
ID = [101; 102; 103; 104];
Name = [“Alice”; “Bob”; “Charlie”; “David”];
Age = [25; 30; 22; 35];
IsStudent = [true; false; true; false];
T = table(ID, Name, Age, IsStudent);
disp(‘元のテーブル:’);
disp(T);

% Age 列の値を全て10増やす
T.Age = T.Age + 10;
disp(‘Age を全て10増やしたテーブル:’);
disp(T);

% Name 列の値を全て大文字にする (丸括弧構文でも可能)
T.Name = upper(T.Name);
disp(‘Name を全て大文字にしたテーブル:’);
disp(T);
“`

出力例:

“`
元のテーブル:
ID Name Age IsStudent
__ __ ___ _
101 “Alice” 25 true
102 “Bob” 30 false
103 “Charlie” 22 true
104 “David” 35 false

Age を全て10増やしたテーブル:
ID Name Age IsStudent
__ __ ___ _
101 “Alice” 35 true
102 “Bob” 40 false
103 “Charlie” 32 true
104 “David” 45 false

Name を全て大文字にしたテーブル:
ID Name Age IsStudent
__ __ ___ ___
101 “ALICE” 35 true
102 “BOB” 40 false
103 “CHARLIE” 32 true
104 “DAVID” 45 false
“`

条件に基づく値の変更

論理インデックスとドット構文または波括弧構文を組み合わせて、特定の条件を満たすセルの値を変更できます。

“`matlab
% 元のテーブルに戻す(例として)
ID = [101; 102; 103; 104];
Name = [“Alice”; “Bob”; “Charlie”; “David”];
Age = [25; 30; 22; 35];
IsStudent = [true; false; true; false];
T = table(ID, Name, Age, IsStudent);
disp(‘元のテーブル:’);
disp(T);

% Ageが30以上の人の IsStudent を true に変更
condition = T.Age >= 30;
T.IsStudent(condition) = true; % ドット構文と論理インデックス
disp(‘Age >= 30 の人の IsStudent を true に変更したテーブル:’);
disp(T);

% Ageが25未満の人の Age を NaN に変更
condition2 = T.Age < 25;
T.Age(condition2) = NaN; % 数値列なので NaN が使える
disp(‘Age < 25 の人の Age を NaN に変更したテーブル:’);
disp(T);

% IsStudent が true の人の Name に “(Student)” を追加
condition3 = T.IsStudent;
T.Name(condition3) = T.Name(condition3) + ” (Student)”; % 文字列配列の結合
disp(‘IsStudent が true の人の Name に “(Student)” を追加したテーブル:’);
disp(T);
“`

出力例:

“`
元のテーブル:
ID Name Age IsStudent
__ __ ___ _
101 “Alice” 25 true
102 “Bob” 30 false
103 “Charlie” 22 true
104 “David” 35 false

Age >= 30 の人の IsStudent を true に変更したテーブル:
ID Name Age IsStudent
__ __ ___ _
101 “Alice” 25 true
102 “Bob” 30 true
103 “Charlie” 22 true
104 “David” 35 true

Age < 25 の人の Age を NaN に変更したテーブル:
ID Name Age IsStudent
__ __ ___ _
101 “Alice” NaN true
102 “Bob” 30 true
103 “Charlie” NaN true
104 “David” 35 true

IsStudent が true の人の Name に “(Student)” を追加したテーブル:
ID Name Age IsStudent
__ __ ___ _
101 “Alice (Student)” NaN true
102 “Bob (Student)” 30 true
103 “Charlie (Student)” NaN true
104 “David (Student)” 35 true
“`
論理インデックスを使った条件付き変更は、データの前処理やクレンジングで非常に役立ちます。

3.4. 変数の並べ替え (movevars)

テーブル内の列(変数)の順番を簡単に変更できます。movevars 関数を使用します。

“`matlab
% 元のテーブル
disp(‘元のテーブル:’);
disp(T); % ID, Name, Age, IsStudent の順

% IsStudent 列を最初の列に移動
T = movevars(T, ‘IsStudent’, ‘Before’, ‘ID’);
disp(‘IsStudent を最初の列に移動したテーブル:’);
disp(T);

% Age 列を Name 列の後ろに移動
T = movevars(T, ‘Age’, ‘After’, ‘Name’);
disp(‘Age を Name の後ろに移動したテーブル:’);
disp(T);
“`

出力例:

“`
IsStudent を最初の列に移動したテーブル:
IsStudent ID Name Age
_ __ __ ___
true 101 “Alice (Student)” NaN
true 102 “Bob (Student)” 30
true 103 “Charlie (Student)” NaN
true 104 “David (Student)” 35

Age を Name の後ろに移動したテーブル:
IsStudent ID Name Age
_ __ __ ___
true 101 “Alice (Student)” NaN
true 102 “Bob (Student)” 30
true 103 “Charlie (Student)” NaN
true 104 “David (Student)” 35
``movevarsは、特定の列を指定した列の前 (‘Before’) または後ろ (‘After’`) に移動するのに便利です。また、複数の列をまとめて移動したり、新しい順序をリストで指定したりすることも可能です。

3.5. 変数の名前変更 (renamevars)

列の名前(変数名)を変更できます。

“`matlab
% 元のテーブル(例)
T = table([1;2],[3;4], ‘VariableNames’, {‘Var1’, ‘Var2’});
disp(‘元のテーブル:’);
disp(T);

% ‘Var1’ を ‘Alpha’ に変更
T = renamevars(T, ‘Var1’, ‘Alpha’);
disp(‘変数名を変更したテーブル (単数):’);
disp(T);

% 複数の変数名を変更
T = renamevars(T, {‘Alpha’, ‘Var2’}, {‘Beta’, ‘Gamma’});
disp(‘変数名を変更したテーブル (複数):’);
disp(T);
“`

出力例:

“`
元のテーブル:
Var1 Var2
_ _
1 3
2 4

変数名を変更したテーブル (単数):
Alpha Var2
_ __
1 3
2 4

変数名を変更したテーブル (複数):
Beta Gamma
_ __
1 3
2 4
“`

3.6. 行の名前変更 (rename – table rows)

行名を変更できます。rename 関数と 'RowNames' オプションを使用します。

“`matlab
% 行名付きテーブル(例)
T = table([1;2], ‘VariableNames’, {‘Value’}, ‘RowNames’, {‘RowA’, ‘RowB’});
disp(‘元のテーブル:’);
disp(T);

% ‘RowA’ を ‘FirstRow’ に変更
T = rename(T, ‘RowA’, ‘FirstRow’, ‘RowNames’);
disp(‘行名を変更したテーブル (単数):’);
disp(T);

% 複数の行名を変更
T = rename(T, {‘FirstRow’, ‘RowB’}, {‘Obs1’, ‘Obs2’}, ‘RowNames’);
disp(‘行名を変更したテーブル (複数):’);
disp(T);
“`

出力例:

“`
元のテーブル:
Value
_____
RowA 1
RowB 2

行名を変更したテーブル (単数):
Value
_____
FirstRow 1
RowB 2

行名を変更したテーブル (複数):
Value
_____
Obs1 1
Obs2 2
“`

4. tableデータの結合と分割

複数のテーブルを組み合わせたり、一つのテーブルを複数の部分に分けたりする操作は、複雑なデータセットを扱う際によく必要になります。

4.1. テーブルの結合

垂直方向の結合 (vertcat)

同じ変数名とデータ型を持つテーブルを、行方向に結合します。これは、新しい観測データを既存のテーブルに追加する操作に似ています。

“`matlab
% テーブル1
T1 = table([101; 102], [“Alice”; “Bob”], [25; 30], …
‘VariableNames’, {‘ID’, ‘Name’, ‘Age’});
disp(‘T1:’);
disp(T1);

% テーブル2
T2 = table([103; 104], [“Charlie”; “David”], [22; 35], …
‘VariableNames’, {‘ID’, ‘Name’, ‘Age’});
disp(‘T2:’);
disp(T2);

% 垂直結合
T_combined_vert = vertcat(T1, T2);
disp(‘vertcat で結合したテーブル:’);
disp(T_combined_vert);
“`

出力例:

“`
T1:
ID Name Age
__ ______ ___
101 “Alice” 25
102 “Bob” 30

T2:
ID Name Age
__ ______ ___
103 “Charlie” 22
104 “David” 35

vertcat で結合したテーブル:
ID Name Age
__ ______ ___
101 “Alice” 25
102 “Bob” 30
103 “Charlie” 22
104 “David” 35
``
変数名とデータ型が一致しない場合、
vertcat` はエラーを発生させます。

水平方向の結合 (horzcat)

同じ行数を持つテーブルを、列方向に結合します。これは、既存の観測データに新しい変数(属性)を追加する操作に似ています。

“`matlab
% テーブルA
TA = table([101; 102; 103; 104], [“Alice”; “Bob”; “Charlie”; “David”], …
‘VariableNames’, {‘ID’, ‘Name’});
disp(‘TA:’);
disp(TA);

% テーブルB
TB = table([25; 30; 22; 35], [true; false; true; false], …
‘VariableNames’, {‘Age’, ‘IsStudent’});
disp(‘TB:’);
disp(TB);

% 水平結合
T_combined_horz = horzcat(TA, TB);
disp(‘horzcat で結合したテーブル:’);
disp(T_combined_horz);
“`

出力例:

“`
TA:
ID Name
__ ______
101 “Alice”
102 “Bob”
103 “Charlie”
104 “David”

TB:
Age IsStudent
___ ___
25 true
30 false
22 true
35 false

horzcat で結合したテーブル:
ID Name Age IsStudent
__ __ ___ _
101 “Alice” 25 true
102 “Bob” 30 false
103 “Charlie” 22 true
104 “David” 35 false
``horzcat` を使う場合、結合する両方のテーブルの行数が一致している必要があります。

共通キーに基づく結合 (join)

データベースの結合操作と同様に、一つ以上の共通の列(キー変数)の値に基づいてテーブルを結合します。これはリレーショナルデータ構造において非常に強力な操作です。

“`matlab
% 学生情報テーブル
students = table([101; 103; 105], [“Alice”; “Charlie”; “Eve”], [“Math”; “Physics”; “Chemistry”], …
‘VariableNames’, {‘StudentID’, ‘Name’, ‘Major’});
disp(‘students table:’);
disp(students);

% 成績情報テーブル
grades = table([101; 102; 103; 101; 103], [85; 92; 78; 88; 81], …
‘VariableNames’, {‘StudentID’, ‘Score’});
disp(‘grades table:’);
disp(grades);

% StudentID をキーとして内部結合 (Inner Join)
% 共通する StudentID を持つ行だけが結合される
innerJoined = join(students, grades, ‘Keys’, ‘StudentID’);
disp(‘StudentID で内部結合したテーブル:’);
disp(innerJoined);

% StudentID をキーとして左結合 (Left Join)
% students テーブルの全ての行が保持され、grades に対応する行がない場合は欠損値 (NaN) が入る
leftJoined = join(students, grades, ‘Keys’, ‘StudentID’, ‘Type’, ‘left’);
disp(‘StudentID で左結合したテーブル:’);
disp(leftJoined);

% StudentID をキーとして外部結合 (Outer Join)
% どちらかのテーブルに存在する全ての StudentID が保持され、対応するデータがない場合は欠損値が入る
outerJoined = join(students, grades, ‘Keys’, ‘StudentID’, ‘Type’, ‘outer’);
disp(‘StudentID で外部結合したテーブル:’);
disp(outerJoined);
“`

出力例:

“`
students table:
StudentID Name Major
___ __ _
101 “Alice” “Math”
103 “Charlie” “Physics”
105 “Eve” “Chemistry”

grades table:
StudentID Score
___ _____
101 85
102 92
103 78
101 88
103 81

StudentID で内部結合したテーブル:
StudentID Name Major Score
___ __ _ _____
101 “Alice” “Math” 85
101 “Alice” “Math” 88
103 “Charlie” “Physics” 78
103 “Charlie” “Physics” 81

StudentID で左結合したテーブル:
StudentID Name Major Score
___ __ _ _____
101 “Alice” “Math” 85
103 “Charlie” “Physics” 78
105 “Eve” “Chemistry” NaN
101 “Alice” “Math” 88
103 “Charlie” “Physics” 81

StudentID で外部結合したテーブル:
StudentID Name Major Score
___ __ _ _____
101 “Alice” “Math” 85
103 “Charlie” “Physics” 78
105 “Eve” “Chemistry” NaN
102 NaN NaN 92
101 “Alice” “Math” 88
103 “Charlie” “Physics” 81
``join` 関数は、異なるデータソースや異なる観測粒度を持つデータを統合する際に非常に重要です。キー変数に複数の列を指定することも可能です。

4.2. テーブルの分割

テーブルを特定の条件やグループに基づいて複数のサブテーブルに分割したい場合があります。

条件に基づく分割

論理インデックスを使って、特定の条件を満たす行と満たさない行に分けることができます。

“`matlab
% 元のテーブル(例)
T = table([101; 102; 103; 104; 105], [25; 30; 22; 35; 28], …
[“A”; “B”; “A”; “C”; “B”], ‘VariableNames’, {‘ID’, ‘Age’, ‘Group’});
disp(‘元のテーブル:’);
disp(T);

% Age >= 30 の条件
condition = T.Age >= 30;

% 条件を満たす行のテーブル
T_adults = T(condition, :);
disp(‘Age >= 30 のテーブル:’);
disp(T_adults);

% 条件を満たさない行のテーブル
T_youngsters = T(~condition, :);
disp(‘Age < 30 のテーブル:’);
disp(T_youngsters);
“`

出力例:

“`
元のテーブル:
ID Age Group
__ ___ _
101 25 “A”
102 30 “B”
103 22 “A”
104 35 “C”
105 28 “B”

Age >= 30 のテーブル:
ID Age Group
__ ___ _
102 30 “B”
104 35 “C”

Age < 30 のテーブル:
ID Age Group
__ ___ _
101 25 “A”
103 22 “A”
105 28 “B”
“`

グループごとの分割 (findgroups, splitapply)

特定のカテゴリ変数(グループ変数)の値に基づいて行をグループ化し、グループごとに異なる処理(分割、集計など)を行いたい場合があります。findgroups 関数はグループのインデックスを作成し、splitapply 関数はそのグループインデックスを使ってグループごとの処理を適用します。

“`matlab
% 元のテーブル(例)
T = table([101; 102; 103; 104; 105], [25; 30; 22; 35; 28], …
[“A”; “B”; “A”; “C”; “B”], [150; 160; 155; 170; 165], …
‘VariableNames’, {‘ID’, ‘Age’, ‘Group’, ‘Score’});
disp(‘元のテーブル:’);
disp(T);

% ‘Group’ 列に基づいてグループを作成
[G, groupNames] = findgroups(T.Group);

% グループごとのテーブルに分割 (これは splitapply が内部的に行いますが、明示的に分割するなら例えば cellfun + indexing)
% 一般的には splitapply で直接処理することが多い

% 例:グループごとの平均スコアを計算
meanScoreByGroup = splitapply(@mean, T.Score, G);

% 結果をテーブルにまとめる
summaryTable = table(groupNames, meanScoreByGroup, …
‘VariableNames’, {‘Group’, ‘MeanScore’});
disp(‘グループごとの平均スコア:’);
disp(summaryTable);
“`

出力例:

“`
元のテーブル:
ID Age Group Score
__ ___ _ _____
101 25 “A” 150
102 30 “B” 160
103 22 “A” 155
104 35 “C” 170
105 28 “B” 165

グループごとの平均スコア:
Group MeanScore
_ ___
“A” 152.5
“B” 162.5
“C” 170
``findgroupssplitapplyは、table` を使った高度な集計処理やグループ別分析の基盤となる関数です。

5. tableデータの集計と変換

データから統計量を計算したり、データの形式を変更したりする操作は、解析の次のステップとして不可欠です。

5.1. 行方向の集計 (varfun)

各列に対して集計関数(例:平均、合計、最小値、最大値など)を適用し、結果を新しいテーブルとして得ることができます。varfun 関数を使用します。

“`matlab
% 元のテーブル(数値列を含む)
T = table([1;2;3], [10;20;30], [100;200;300], …
‘VariableNames’, {‘Data1’, ‘Data2’, ‘Data3’});
disp(‘元のテーブル:’);
disp(T);

% 各列の平均を計算
meanOfColumns = varfun(@mean, T);
disp(‘各列の平均 (varfun):’);
disp(meanOfColumns); % 結果はテーブルになる

% 特定の列に対して集計関数を適用
meanOfSelectedColumns = varfun(@mean, T, ‘InputVariables’, {‘Data1’, ‘Data3’});
disp(‘特定の列の平均 (varfun):’);
disp(meanOfSelectedColumns);

% 複数の集計関数を適用
summaryOfColumns = varfun({@mean, @sum, @max}, T);
disp(‘各列の平均、合計、最大値 (varfun):’);
disp(summaryOfColumns); % 新しい変数名が自動で付加される
“`

出力例:

“`
元のテーブル:
Data1 Data2 Data3
_ __
1 10 100
2 20 200
3 30 300

各列の平均 (varfun):
mean_Data1 mean_Data2 mean_Data3
_ _ ____
2 20 200

特定の列の平均 (varfun):
mean_Data1 mean_Data3
_ _
2 200

各列の平均、合計、最大値 (varfun):
mean_Data1 sum_Data1 max_Data1 mean_Data2 sum_Data2 max_Data2 mean_Data3 sum_Data3 max_Data3
_ __ _ _ __ _ _ __ _
2 6 3 20 60 30 200 600 300
``varfun` は、数値列に対して様々な統計量を一括で計算するのに非常に便利です。

5.2. グループごとの集計 (groupsummary)

findgroupssplitapply の組み合わせは強力ですが、最も一般的な「グループごとの集計」に特化した関数が groupsummary です。これにより、指定したグループ変数に基づいてデータをグループ化し、指定した集計変数に対して指定した集計関数を適用して、結果をサマリーテーブルとして得ることができます。

“`matlab
% 元のテーブル(例)
T = table([101; 102; 103; 104; 105; 106], [25; 30; 22; 35; 28; 40], …
[“A”; “B”; “A”; “C”; “B”; “C”], [150; 160; 155; 170; 165; 175], …
[“Male”; “Female”; “Male”; “Female”; “Male”; “Female”], …
‘VariableNames’, {‘ID’, ‘Age’, ‘Group’, ‘Score’, ‘Gender’});
disp(‘元のテーブル:’);
disp(T);

% ‘Group’ に基づいてグループ化し、’Score’ の平均を計算
summaryByGroup = groupsummary(T, ‘Group’, ‘mean’, ‘Score’);
disp(‘Group ごとの Score 平均:’);
disp(summaryByGroup);

% ‘Group’ と ‘Gender’ に基づいてグループ化し、’Age’ と ‘Score’ の平均と合計を計算
summaryByGroupAndGender = groupsummary(T, {‘Group’, ‘Gender’}, {‘mean’, ‘sum’}, {‘Age’, ‘Score’});
disp(‘Group および Gender ごとの Age と Score の平均・合計:’);
disp(summaryByGroupAndGender);
“`

出力例:

“`
Group ごとの Score 平均:
Group GroupCount mean_Score
_ _ _
“A” 2 152.5
“B” 2 162.5
“C” 2 172.5

Group および Gender ごとの Age と Score の平均・合計:
Group Gender GroupCount mean_Age sum_Age mean_Score sum_Score
_ _ _ _ _ __ ___
“A” “Male” 2 23.5 47 152.5 305
“B” “Female” 1 30 30 160 160
“B” “Male” 1 28 28 165 165
“C” “Female” 2 37.5 75 172.5 345
``groupsummaryは、データフレームのgroupby().agg()と同等の機能を提供し、複雑なクロス集計や要約統計量の計算を簡単に行うことができます。‘GroupCount’` 列は各グループの観測数を示します。

5.3. データの変換 (rowfun)

varfun が列に関数を適用するのに対し、rowfun は各行に関数を適用し、結果を新しいテーブルとして得ることができます。これは、行ごとに計算や処理が必要な場合に便利です。

“`matlab
% 元のテーブル(例)
T = table([1; 2; 3], [10; 20; 30], ‘VariableNames’, {‘A’, ‘B’});
disp(‘元のテーブル:’);
disp(T);

% 各行の A と B の合計を計算する無名関数
sumAB = @(a, b) a + b;

% 各行に関数を適用
resultTable = rowfun(sumAB, T, ‘InputVariables’, {‘A’, ‘B’}, ‘OutputVariableNames’, {‘Sum_A_B’});
disp(‘rowfun で各行の合計を計算したテーブル:’);
disp(resultTable);

% 各行の A と B を要素とするベクトルを作成
vecAB = @(a, b) [a, b];
resultTable2 = rowfun(vecAB, T, ‘InputVariables’, {‘A’, ‘B’}, ‘OutputVariableNames’, {‘Vector_AB’});
disp(‘rowfun で各行のベクトルを作成したテーブル:’);
disp(resultTable2);
“`

出力例:

“`
元のテーブル:
A B
__ __
1 10
2 20
3 30

rowfun で各行の合計を計算したテーブル:
Sum_A_B
_
11
22
33

rowfun で各行のベクトルを作成したテーブル:
Vector_AB
___
[1 10]
[2 20]
[3 30]
``rowfun` は、テーブルの各行を独立したデータポイントとして扱い、複雑なカスタム関数を適用する際に役立ちます。

5.4. 欠損値の処理

現実世界のデータには欠損値(missing values)がしばしば含まれます。MATLABのtableは欠損値を効果的に扱うための機能を提供します。数値型の欠損値は NaN で表現されますが、他の型(string, categorical, datetimeなど)の欠損値もサポートされます。

  • 欠損値の特定: ismissing 関数は、テーブル内の各要素が欠損値であるかどうかを示す論理配列を返します。
  • 欠損値の標準化: standardizeMissing 関数は、特定の値を欠損値として扱うように変換します(例:文字列 “N/A” や数値 -999 を欠損値としてマーク)。
  • 欠損値の補完: fillmissing 関数は、様々な方法(平均値、中央値、線形補間、前後の値など)で欠損値を補完します。
  • 欠損値を含む行/列の削除: rmmissing 関数は、欠損値を含む行または列を削除します。

“`matlab
% 欠損値を含むテーブルを作成
T = table([1; 2; NaN; 4; 5], [“A”; “B”; “C”; “”; “E”], [true; false; true; NaN; false], …
‘VariableNames’, {‘NumData’, ‘StrData’, ‘LogData’});
T.StrData(2) = ““; % 文字列の欠損値
T.LogData(4) = NaN; % 論理型の欠損値(内部的には double NaN)

disp(‘欠損値を含む元のテーブル:’);
disp(T);

% 欠損値の位置を確認
missingIndices = ismissing(T);
disp(‘欠損値の位置を示す論理配列:’);
disp(missingIndices);

% 欠損値を補完 (数値列を平均値で、文字列列を特定の文字列で補完)
T_filled = fillmissing(T, ‘mean’, ‘DataVariables’, ‘NumData’); % 数値列を平均値で補完
T_filled = fillmissing(T_filled, ‘constant’, ‘DataVariables’, ‘StrData’, ‘Constant’, ‘UNKNOWN’); % 文字列列を定数で補完
% 論理型は補完が難しい場合がある(文脈による)

disp(‘欠損値を補完したテーブル:’);
disp(T_filled);

% 欠損値を含む行を削除
T_rmrows = rmmissing(T);
disp(‘欠損値を含む行を削除したテーブル:’);
disp(T_rmrows);

% 欠損値を含む列を削除
T_rmcols = rmmissing(T, 2); % 次元 2 (列) を指定
disp(‘欠損値を含む列を削除したテーブル:’);
disp(T_rmcols);
“`

出力例:

“`
欠損値を含む元のテーブル:
NumData StrData LogData
_ ___ _
1 “A” true
2 false
NaN “C” true
4 “” NaN
5 “E” false

欠損値の位置を示す論理配列:
1 0 0
0 1 0
1 0 0
0 1 1
0 0 0

欠損値を補完したテーブル:
NumData StrData LogData
_ ___ _
1 “A” true
2 “UNKNOWN” false
3 “C” true
4 “” NaN
5 “E” false
% 注意:NumData の NaN は補完され、StrData の は補完されたが、” (空文字列) は補完されない
% LogData の NaN も補完されない(fillmissing は数値型に主に特化)

欠損値を含む行を削除したテーブル:
NumData StrData LogData
_ _ _
1 “A” true
5 “E” false

欠損値を含む列を削除したテーブル:
NumData
_
1
2
NaN
4
5
“`
欠損値処理関数は、データクレンジングパイプラインの重要なステップです。補完方法や削除戦略は、データの種類や解析の目的に応じて慎重に選択する必要があります。

5.5. データの並べ替え (sortrows)

テーブルの行を、一つ以上の列の値に基づいて並べ替えることができます。sortrows 関数を使用します。

“`matlab
% 元のテーブル
T = table([103; 101; 104; 102], [22; 25; 35; 30], …
[“Charlie”; “Alice”; “David”; “Bob”], …
‘VariableNames’, {‘ID’, ‘Age’, ‘Name’});
disp(‘元のテーブル:’);
disp(T);

% Age 列で昇順に並べ替え
T_sorted_age = sortrows(T, ‘Age’);
disp(‘Age で昇順に並べ替えたテーブル:’);
disp(T_sorted_age);

% Age 列で降順に並べ替え
T_sorted_age_desc = sortrows(T, ‘Age’, ‘descend’);
disp(‘Age で降順に並べ替えたテーブル:’);
disp(T_sorted_age_desc);

% Name 列で昇順に並べ替え
T_sorted_name = sortrows(T, ‘Name’);
disp(‘Name で昇順に並べ替えたテーブル:’);
disp(T_sorted_name);

% Age で昇順、次に ID で昇順に並べ替え (複数のキー)
T_sorted_multiple = sortrows(T, {‘Age’, ‘ID’});
disp(‘Age で昇順、次に ID で昇順に並べ替えたテーブル:’);
disp(T_sorted_multiple);
“`

出力例:

“`
元のテーブル:
ID Age Name
__ ___ _
103 22 “Charlie”
101 25 “Alice”
104 35 “David”
102 30 “Bob”

Age で昇順に並べ替えたテーブル:
ID Age Name
__ ___ _
103 22 “Charlie”
101 25 “Alice”
102 30 “Bob”
104 35 “David”

Age で降順に並べ替えたテーブル:
ID Age Name
__ ___ _
104 35 “David”
102 30 “Bob”
101 25 “Alice”
103 22 “Charlie”

Name で昇順に並べ替えたテーブル:
ID Age Name
__ ___ _
101 25 “Alice”
102 30 “Bob”
103 22 “Charlie”
104 35 “David”

Age で昇順、次に ID で昇順に並べ替えたテーブル:
ID Age Name
__ ___ _
103 22 “Charlie”
101 25 “Alice”
102 30 “Bob”
104 35 “David”
``sortrows` は、データを特定の順序で確認したり、時系列データを処理したりする際に非常に役立ちます。

6. tableデータの視覚化

table形式のデータは、そのままプロット関数に渡して視覚化することができます。MATLABの多くのプロット関数はtable入力をサポートしており、変数名を指定して簡単にグラフを作成できます。

“`matlab
% データの準備
Height = [1.65; 1.72; 1.58; 1.80; 1.70];
Weight = [58; 65; 52; 75; 63];
Gender = categorical([“Female”; “Male”; “Female”; “Male”; “Female”]); % カテゴリカル型が便利
Data = table(Height, Weight, Gender, ‘VariableNames’, {‘Height_m’, ‘Weight_kg’, ‘Gender’});

disp(‘プロット用テーブル:’);
disp(Data);

% 身長 vs 体重 の散布図をプロット
figure;
plot(Data, ‘Height_m’, ‘Weight_kg’, ‘o’); % x軸に ‘Height_m’, y軸に ‘Weight_kg’ を指定
title(‘身長 vs 体重’);
xlabel(‘身長 (m)’);
ylabel(‘体重 (kg)’);
grid on;

% 性別ごとに色分けした散布図
figure;
gscatter(Data.Height_m, Data.Weight_kg, Data.Gender); % tableの列を抽出してgscatterに渡す
title(‘身長 vs 体重 (性別ごと)’);
xlabel(‘身長 (m)’);
ylabel(‘体重 (kg)’);
legend(‘Location’, ‘best’);
grid on;

% stackedplot を使って複数の数値変数をプロット
figure;
stackedplot(Data, {‘Height_m’, ‘Weight_kg’}); % 複数の数値列を指定
title(‘身長と体重のスタックプロット’);

% boxchart を使ってカテゴリごとの分布をプロット
figure;
boxchart(Data.Gender, Data.Weight_kg); % カテゴリカル変数と数値列を指定
title(‘性別ごとの体重分布’);
xlabel(‘性別’);
ylabel(‘体重 (kg)’);
“`

MATLABのプロット関数にtableを渡すことで、煩雑なデータ準備コードを減らし、変数名を直接使用して意図を明確にすることができます。特にR2018a以降、新しいプロット関数(tiledlayout, nexttile, boxchart, swarmchart, violinplot, heatmap, wordcloudなど)がtable入力を積極的にサポートしています。

7. 高度なtable操作とテクニック

7.1. カテゴリカル変数 (categorical) の活用

性別、都道府県、実験条件など、限られた数の離散的なカテゴリを持つデータは、categorical 型として扱うとメモリ効率が良く、特定の操作(例:グループ化、集計)が容易になります。readtable は文字列を自動的にカテゴリカル型に変換することもありますが、明示的に変換することも可能です。

“`matlab
% 文字列配列からカテゴリカル配列を作成
cities_str = [“Tokyo”; “Osaka”; “Tokyo”; “Sapporo”; “Osaka”];
cities_cat = categorical(cities_str);

% tableに入れる
T = table(cities_str, cities_cat, ‘VariableNames’, {‘City_String’, ‘City_Categorical’});
disp(‘カテゴリカル変数を含むテーブル:’);
disp(T);

% カテゴリカル変数のカテゴリを確認
categories(T.City_Categorical);

% カテゴリカル変数を使って簡単にグループ化・集計
% findgroups や groupsummary でカテゴリカル変数をグループ変数として直接使用できる
% summaryByCity = groupsummary(T, ‘City_Categorical’, ‘mean’, ‘…’); % 他の数値変数があれば集計できる
“`
カテゴリカル変数は、データの種類を正確に表現し、後続の分析(統計モデル、機械学習など)で正しく扱われるために重要です。

7.2. 時間指定データ (timetable) への変換

日付や時間の情報を持つテーブルは、timetable という特殊なtableに変換することで、時系列データに特化した強力な機能(リサンプリング、同期、時間による抽出など)を利用できるようになります。timetable は、行名が順序付けされたユニークな日付・時間値であるtableです。

“`matlab
% 時間データを含むテーブル
Time = datetime({‘2023-01-01’; ‘2023-01-02’; ‘2023-01-03’});
Value1 = [10; 12; 15];
Value2 = [100; 110; 105];
T = table(Time, Value1, Value2);

% 時系列テーブルに変換
TT = table2timetable(T);
disp(‘timetable:’);
disp(TT);

% timetableのデータに時間を使ってアクセス
TT_Jan2 = TT(‘2023-01-02’, :);
disp(‘2023-01-02 のデータ:’);
disp(TT_Jan2);

% リサンプリング (例:日次から週次へ)
% weeklyTT = retime(TT, ‘weekly’, ‘mean’);
``
時系列データを扱う場合は、可能な限り
timetable` を使用することを強く推奨します。

7.3. tableを使った効率的なデータ前処理パイプラインの構築

table を中心に据えることで、データ読み込みから前処理、集計、可視化までの一連の作業を、一貫性のある分かりやすいコードで記述できます。パイプラインを構築する際の一般的なステップは以下のようになります。

  1. 読み込み: readtable でデータを読み込む。オプションで変数型などを指定。
  2. 整理: 不要な列の削除 (T(:, 'VarName') = [])、変数名の変更 (renamevars)、列の順序変更 (movevars)。
  3. クレンジング: 欠損値の特定 (ismissing)、標準化 (standardizeMissing)、補完 (fillmissing) または削除 (rmmissing)。外れ値の特定と処理。
  4. 変換: データ型の変換(例:string から categorical へ)、新しい派生列の計算(例:既存の列から BMI を計算して新しい列として追加)。
  5. フィルタリング: 条件に基づく行の抽出 (T(logicalIndex, :))。
  6. 結合: 複数のデータソースを joinvertcat で統合。
  7. 集計: グループごとの統計量の計算 (groupsummary)、列全体の統計量計算 (varfun)。

これらのステップを、MATLABのtable関数を使って順に実行していくことで、再現性が高く、メンテナンスしやすいデータ前処理スクリプトを作成できます。

8. 他のデータ構造との比較

改めて、MATLABのtableを他の主要なデータ構造と比較してみましょう。

  • 配列 (Numeric Arrays):

    • Pros: 数値計算に特化しており、非常に高速。メモリ効率が良い(特に大量の数値データ)。線形代数演算など、MATLABのコア機能との親和性が高い。
    • Cons: 同じデータ型しか格納できない。列や行に名前がなく、インデックス番号でしかアクセスできないため、データの意味がコードから分かりにくい。
    • table と比較: table は柔軟性、可読性、混合データ型対応で優れる。配列は純粋な数値計算性能で優れる。table 内の数値列は、必要に応じて配列として抽出 (T.NumericColumn) して高速な計算に使用できる。
  • 構造体 (Structs):

    • Pros: フィールド名で異なる型のデータを管理できる。個々の「レコード」を表現するのに適している(例:patient.name, patient.age, patient.diagnosis)。
    • Cons: 列指向の操作(例:全患者の年齢の平均)は、フィールドごとにループしたりセル配列に変換したりする必要があり、煩雑になりがち。
    • table と比較: table は列指向の操作や集計、フィルタリングが非常に得意。構造体はレコード指向のデータ管理に適している。構造体の配列とtableは似ているが、tableの方がデータフレーム的な操作関数が豊富。
  • セル配列 (Cell Arrays):

    • Pros: 非常に柔軟で、異なる型のデータを任意の構造で格納できる。
    • Cons: データの構造が明確になりにくく、特定の要素にアクセスしたり操作したりする際に、インデックス付けや cellfun の使用が必要になり、コードが読みにくくエラーが発生しやすい。テーブル形式のデータであっても、セル配列で扱うと構造が失われがち。
    • table と比較: table はセル配列の「異なる型を格納できる」という柔軟性を持ちつつ、明確な構造(列名、行名)と豊富な操作関数を提供することで、データ処理の効率と可読性を大幅に向上させる。表形式データであれば、ほとんどの場合セル配列よりtableを使うべき。

結論として、表形式のデータ、特に異なるデータ型が混在するデータや、列(変数)や行(観測)に意味のある名前を付けたいデータ、そして頻繁にフィルタリング、集計、結合といったデータ操作を行いたいデータについては、table がMATLABにおける最適なデータ構造と言えます。

9. まとめ:tableを使いこなしてデータ処理を効率化しよう

この記事では、MATLABのtableクラスについて、その基本的な作成方法から、データへのアクセス、操作、結合、分割、集計、変換、そして視覚化に至るまで、データ処理に役立つ様々な使い方を詳細に解説しました。

table は、従来のMATLABデータ構造(配列、構造体、セル配列)の限界を補い、RのデータフレームやPythonのpandas DataFrameと同様の、強力かつ直感的な表形式データ処理機能を提供します。変数名や行名を使ったアクセス、論理インデックスによるフィルタリング、readtable, writetable, join, groupsummary, varfun, rowfun, fillmissing, sortrows といった豊富な関数群は、データサイエンス、統計解析、実験データ処理など、幅広い分野であなたの作業を劇的に効率化してくれるでしょう。

table を使いこなすことのメリットを再確認しましょう:

  • コードの可読性と保守性の向上: 変数名でデータにアクセスすることで、コードが何をしているのかが明確になります。
  • 多様なデータ型への対応: 数値、文字列、カテゴリカル、論理値、日付・時間など、混在するデータを一つの構造で扱えます。
  • 効率的なデータ操作: 組み込み関数や直感的な構文により、フィルタリング、集計、結合といった複雑な操作も簡単に行えます。
  • 他のツールボックスとの連携: 統計、機械学習、データ分析系の多くの関数がtable入力をサポートしています。

この記事で解説した内容が、あなたがMATLABでのデータ処理においてtableを自信を持って活用するための出発点となれば幸いです。MATLABのヘルプドキュメントや、MathWorksのウェブサイトで公開されている様々な例も参考にしながら、ぜひ実際に手を動かしてtableの便利さを体験してみてください。

データ処理は、どんな解析においても最初の、そして最も時間のかかるステップの一つです。tableを効果的に利用することで、この重要なステップをより迅速に、正確に、そして楽しく進めることができるはずです。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール