NaNとは?データ分析で頻出する「数値ではない」を表す特殊な値を解説

プログラミング・IT

プログラミングやデータ分析をしていると、突然NaNという表示に遭遇することがあります。

「エヌエーエヌ?ナン?何これ?」
「データが消えちゃった?」

実は、NaNは「Not a Number」(数値ではない)の略で、計算結果が数値として表せない時に現れる特殊な値なんです。

エラーとは少し違いますが、NaNをそのままにしておくと様々な問題が起こります。

今回は、NaNの基本的な意味から、発生する原因、各プログラミング言語での扱い方、そして実務での対処法まで、分かりやすく解説していきますね。

スポンサーリンク

NaNとは?基本を理解しよう

Not a Number(数値ではない)

NaNは「Not a Number」の頭文字を取った略語で、数値として扱えない値を表す特殊な記号です。

読み方は「ナン」または「エヌエーエヌ」。

NaNの特徴:

  • 計算結果が数値にならない時に発生
  • エラーではなく「特殊な値」として扱われる
  • そのまま計算を続けると、結果もNaNになる
  • データ分析では頻繁に遭遇する

例えば、「りんご ÷ 2」のように、文字を数値で割ろうとするとNaNが発生します。

NaNはどこで使われる?

NaNは様々なプログラミング言語やツールで使われています:

  • Python(Pandas、NumPyなど)
  • JavaScript
  • Excel / Google スプレッドシート
  • R言語
  • SQL(一部のデータベース)
  • MATLAB

データを扱うほとんどの環境で、NaNに遭遇する可能性があります。

NaNが発生する主な原因

不適切な計算

数学的に定義できない計算を行うと、NaNが発生します。

例1:0で0を割る

import numpy as np
result = 0 / 0  # Pythonではエラー
result = np.float64(0) / np.float64(0)  # NaNになる

通常の0除算(例:5 ÷ 0)は無限大(inf)やエラーになりますが、0 ÷ 0 は NaN です。

例2:負の数の平方根

Math.sqrt(-1)  // NaN
// 虚数は実数の範囲では表せない

例3:数値への変換失敗

parseInt("こんにちは")  // NaN
// 文字列を数値に変換できない

データの欠損

データ分析では、欠損値(missing value)がNaNとして表現されます。

例:アンケートデータ

名前    年齢    収入
田中    28     500万
佐藤    35     NaN(未回答)
鈴木    NaN    600万(年齢不明)

データが入力されていない、または取得できなかった場合にNaNが使われます。

ファイルの読み込みエラー

CSVファイルなどを読み込む際、データの形式が正しくないとNaNになることがあります。

例:数値列に文字が混入

商品ID,価格
001,1000
002,無料  ← これがNaNになる
003,1500

「無料」という文字は数値に変換できないため、NaNとして読み込まれます。

計算の伝播

NaNを含む計算は、結果もNaNになります。

x = float('nan')
y = 10
result = x + y  # NaN(NaN + 10 = NaN)

1つでもNaNがあると、それが次々と広がっていく——これがNaNの伝播です。

各言語でのNaNの扱い方

Python(Pandas、NumPy)

Pythonのデータ分析では、NaNが頻繁に登場します。

NaNの作成:

import numpy as np
import pandas as pd

# NaNを作る
nan_value = float('nan')
nan_value = np.nan

NaNの判定:

import pandas as pd

x = float('nan')

# 間違った判定方法
x == float('nan')  # False(NaN同士は等しくない!)

# 正しい判定方法
pd.isna(x)  # True
np.isnan(x)  # True

重要なポイント: NaNは自分自身とも等しくありません(NaN != NaN は True)。

NaNの処理:

import pandas as pd

df = pd.DataFrame({
    'A': [1, 2, np.nan, 4],
    'B': [5, np.nan, 7, 8]
})

# NaNを含む行を削除
df.dropna()

# NaNを特定の値で埋める
df.fillna(0)

# NaNを平均値で埋める
df.fillna(df.mean())

JavaScript

JavaScriptでは、計算エラーの結果としてNaNが返されます。

NaNの発生:

// 文字列を数値に変換しようとする
Number("hello")  // NaN
parseInt("abc")  // NaN

// 不正な計算
0 / 0  // NaN
Math.sqrt(-1)  // NaN

NaNの判定:

let x = NaN;

// 間違った方法
x == NaN  // false
x === NaN  // false

// 正しい方法
isNaN(x)  // true
Number.isNaN(x)  // true(より厳密)

NaNの処理:

let value = parseInt("abc");

// デフォルト値を設定
let result = isNaN(value) ? 0 : value;

// または、論理演算子を使用
let result2 = value || 0;

Excel / Google スプレッドシート

Excelでは、NaNは直接は表示されませんが、類似の概念があります。

エラー値:

  • #VALUE!:データ型が正しくない
  • #DIV/0!:0で割った
  • #N/A:データが見つからない

対処方法:

=IFERROR(A1/B1, 0)
// エラーが出たら0を返す

=IFNA(VLOOKUP(...), "データなし")
// #N/Aエラーを処理

R言語

Rでは、NaNとNAが区別されています。

NaNとNAの違い:

  • NaN:計算結果が数値にならない(0/0など)
  • NA:データが欠損している(Not Available)
x <- 0/0  # NaN
y <- NA   # 欠損値

is.nan(x)  # TRUE
is.na(x)   # TRUE(NaNはNAでもある)
is.na(y)   # TRUE
is.nan(y)  # FALSE(NAはNaNではない)

NaNとその他の特殊値との違い

NaNとNull(None)の違い

混同しやすい概念ですが、意味が異なります。

NaN:

  • 「数値として無効」を表す
  • 計算結果として発生
  • 数値型の一種

Null(Pythonでは None):

  • 「値が存在しない」を表す
  • データが未定義、未設定
  • 独立した型

例:

# NaN:計算の結果
age = float('nan')  # 年齢が不明(数値として無効)

# None:データの不在
name = None  # 名前がまだ設定されていない

NaNとInfinity(無限大)の違い

NaN:

  • 数値として定義できない
  • 例:0 ÷ 0、負の数の平方根

Infinity(inf):

  • 無限大を表す
  • 例:1 ÷ 0 = 正の無限大、-1 ÷ 0 = 負の無限大
import numpy as np

np.float64(0) / np.float64(0)  # NaN
np.float64(1) / np.float64(0)  # inf(無限大)

NaNと空文字列の違い

NaN:

  • 数値型の特殊な値
  • 計算に使うとNaNが伝播

空文字列(””):

  • 文字列型で、内容が空
  • 連結しても問題なし
x = float('nan')
y = x + 5  # NaN

a = ""
b = a + "hello"  # "hello"(問題なし)

NaNの実務での対処法

発見と確認

まずはデータにNaNがどれくらい含まれているかを確認しましょう。

Pandasでの確認:

import pandas as pd

df = pd.read_csv('data.csv')

# NaNの数を確認
df.isna().sum()

# NaNの割合を確認
df.isna().mean() * 100

# NaNを含む行を表示
df[df.isna().any(axis=1)]

削除する

NaNを含むデータを削除する方法です。

注意点: データ量が減るため、慎重に判断しましょう。

# NaNを含む行を削除
df_cleaned = df.dropna()

# 特定の列のNaNのみ削除
df_cleaned = df.dropna(subset=['age', 'income'])

# 全ての値がNaNの行だけ削除
df_cleaned = df.dropna(how='all')

補完する(埋める)

NaNを他の値で置き換える方法です。

固定値で埋める:

# 0で埋める
df_filled = df.fillna(0)

# 特定の文字列で埋める
df['name'].fillna('不明')

統計値で埋める:

# 平均値で埋める
df['age'].fillna(df['age'].mean())

# 中央値で埋める
df['income'].fillna(df['income'].median())

# 最頻値で埋める
df['category'].fillna(df['category'].mode()[0])

前後の値で埋める:

# 前の値で埋める(forward fill)
df.fillna(method='ffill')

# 後ろの値で埋める(backward fill)
df.fillna(method='bfill')

補間する

数値データでは、前後の値から推定する補間も有効です。

# 線形補間
df['temperature'].interpolate(method='linear')

# 時系列データの補間
df['sales'].interpolate(method='time')

別の列として保持

NaNの有無自体が重要な情報の場合、フラグ列を作成します。

# NaNフラグを作成
df['age_is_missing'] = df['age'].isna().astype(int)

# その後、NaNを適切な値で埋める
df['age'].fillna(df['age'].median())

これにより、「年齢が欠損していた」という情報を保持できます。

NaNが引き起こす問題

計算結果がすべてNaNになる

NaNの伝播により、1つのNaNが全体に影響します。

例:

import pandas as pd

df = pd.DataFrame({
    'A': [1, 2, float('nan'), 4],
    'B': [5, 6, 7, 8]
})

# 合計を計算
df['A'].sum()  # NaN(デフォルトではNaNを含む)

# 対処:NaNを無視して計算
df['A'].sum(skipna=True)  # 7.0

条件分岐が機能しない

NaNは通常の比較演算子では正しく判定できません。

x = float('nan')

if x == float('nan'):  # False(実行されない)
    print("NaNです")

if pd.isna(x):  # True(正しい判定)
    print("NaNです")

データの可視化でエラー

グラフ描画時にNaNがあると、エラーや不自然な表示になることがあります。

対処法:

  • NaNを削除してからプロット
  • NaNを適切な値で埋めてからプロット
  • ライブラリの設定でNaNを自動的に無視

機械学習モデルのエラー

多くの機械学習アルゴリズムは、NaNを含むデータを受け付けません。

対処が必須:

from sklearn.impute import SimpleImputer

# 平均値で補完
imputer = SimpleImputer(strategy='mean')
X_imputed = imputer.fit_transform(X)

NaNを防ぐためのベストプラクティス

データ入力時の検証

データを入力する段階で、NaNの発生を防ぎましょう。

方法:

  • 必須項目の設定
  • データ型の制限
  • 妥当性チェック(年齢は0〜150など)
  • デフォルト値の設定

計算前のチェック

計算を行う前に、NaNの有無を確認する習慣をつけましょう。

if df['column'].isna().any():
    print("警告:NaNが含まれています")
    # 適切な処理を実行

try-exceptでのエラー処理

NaNが発生する可能性がある処理は、エラーハンドリングを行いましょう。

try:
    result = some_calculation()
except ValueError:
    result = float('nan')  # または適切なデフォルト値

ドキュメントへの記載

自分のコードやデータセットに、NaNの扱い方を明記しましょう。

例:

"""
このデータセットについて:
- age列:NaNは「不明」を意味する
- income列:NaNは中央値で補完済み
- category列:NaNを含む行は削除済み
"""

よくある質問と回答

Q1:NaNとNullは同じですか?

A:いいえ、異なる概念です。

  • NaN:数値型で、「数値として無効」を表す
  • Null(None):「値が存在しない」を表す

Pandasでは、両方とも pd.isna() で検出できますが、本来の意味は違います。

Q2:なぜ NaN == NaN は False なのですか?

A:IEEE 754浮動小数点数の仕様で、そう定義されているためです。

理由:

  • NaNは「定義できない値」なので、比較もできない
  • 異なる原因で発生したNaN同士は、同じとは限らない

そのため、判定には isnan()pd.isna() を使います。

Q3:NaNを0に置き換えるべきですか?

A:状況によります。

0で良い場合:

  • カウントデータ(NaNは「0回」を意味する)
  • 加算するデータ(NaNがあっても合計に影響させない)

0が不適切な場合:

  • 平均を計算するデータ(0で埋めると平均が歪む)
  • 重要な欠損情報(NaNの有無自体が意味を持つ)

適切な補完方法を選びましょう。

Q4:Excelの #VALUE! はNaNと同じですか?

A:似ていますが、厳密には異なります。

  • #VALUE!:Excelのエラー表示
  • NaN:プログラミングでの特殊な値

どちらも「計算できない」ことを示す点では共通しています。

まとめ:NaNを正しく理解して適切に対処しよう

NaNは、データ分析やプログラミングで避けては通れない特殊な値です。

この記事のポイント:

  • NaNは「Not a Number」の略で、数値として扱えない値
  • 不適切な計算やデータの欠損で発生する
  • Python、JavaScript、Rなど多くの言語で使われる
  • NaN同士は等しくないため、専用の判定関数を使う
  • NaNが1つあると、計算結果全体がNaNになる(伝播)
  • NullやInfinityとは異なる概念
  • 削除、補完、補間など、状況に応じた対処法がある
  • データ入力時の検証や計算前のチェックで予防できる
  • 機械学習では必ず対処が必要

NaNに遭遇したら、まずは「なぜNaNが発生したのか」を理解することが大切です。

原因を把握した上で、削除するか補完するか、適切な方法を選びましょう。

データ分析の精度を高めるためにも、NaNの正しい理解と適切な処理は欠かせません。

最初は戸惑うかもしれませんが、慣れればNaNは「データの異常を教えてくれる有用なシグナル」として活用できるようになりますよ。

コメント

タイトルとURLをコピーしました