- こんなことで困っていませんか?
- この記事でわかること
- value_counts() とは?
- サンプルデータの作成
- 基本の使い方|件数を数える
- 割合を表示する方法|normalize=True
- パーセント表示にする方法
- 欠損値も数える方法|dropna=False
- 欠損値を含めた割合を表示する方法
- 少ない順に並べたいとき|ascending=True
- 値順に並べたいとき|sort_index()
- よく使う書き方まとめ【比較表】
- value_counts() の結果を表として扱う方法
- 件数と割合をまとめて表示する方法
- value_counts() は表記ゆれの発見にも便利
- 数値データにも使える
- value_counts() の結果はグラフ化にも使える
- value_counts() と groupby().size() と count() の違い
- よくある使い方の例
- 大規模データでの考慮事項
- よくある間違い
- ワンポイント
- まとめ
こんなことで困っていませんか?
Pandasでデータ分析をしていると、次のような場面によく出会います。
- 列の中に同じ値が何件あるか知りたい
- 件数だけでなく割合も見たい
- 欠損値(NaN)が何件あるか確認したい
- groupby() と何が違うのかわからない
- 表記ゆれや入力ミスをすばやく見つけたい
そんなときに便利なのが、value_counts() です。
value_counts() は、1列の中にある値ごとの出現回数を集計するためのメソッドです。Pandasでデータを読み込んだあとに、まず中身をざっくり把握したいときによく使います。
さらに、normalize=True を使えば割合も確認でき、dropna=False を使えば欠損値も含めて数えられます。そのため、単なる件数集計だけでなく、カテゴリの偏り確認、欠損値チェック、表記ゆれの発見にも役立ちます。
この記事では、Pandas初心者向けに value_counts() の基本から、割合表示、欠損値の数え方、表記ゆれの見つけ方、groupby().size() や count() との違いまで、実例つきでわかりやすく解説します。
▶️ value_countsの公式ドキュメントも参考にしてください:
pandas.Series.value_counts Documentation
この記事でわかること
- value_counts() の基本的な使い方がわかる
- 値ごとの件数を集計できる
- 値ごとの割合を表示できる
- 欠損値(NaN)を含めて数えられる
- 表記ゆれやカテゴリの偏りを見つけられる
- groupby().size() や count() との違いがわかる
value_counts() とは?
value_counts() は、Seriesの中にある値ごとの出現回数を数えるメソッドです。
たとえば、会員ランクの列があるときに value_counts() を使うと、Gold が何件、Silver が何件、Bronze が何件あるかをすぐに集計できます。
基本構文は次のとおりです。
df[“列名”].value_counts() まずは、「1列の値の出現回数を数える」と覚えておけば大丈夫です。
サンプルデータの作成
今回は、少し実務に近いサンプルデータを使って説明します。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"member_rank": ["Gold", "Silver", "Gold", "Bronze", np.nan, "Silver", "Gold", "bronze", " Silver "],
"city": ["Tokyo", "Osaka", "Tokyo", "Nagoya", "Tokyo", "osaka", "Tokyo ", "Nagoya", np.nan],
"rating": [5, 4, 5, 3, 4, 4, 5, 3, 4]
})
print(df)
| member_rank | city | rating |
|---|---|---|
| Gold | Tokyo | 5 |
| Silver | Osaka | 4 |
| Gold | Tokyo | 5 |
| Bronze | Nagoya | 3 |
| NaN | Tokyo | 4 |
| Silver | osaka | 4 |
| Gold | Tokyo | 5 |
| bronze | Nagoya | 3 |
| Silver | NaN | 4 |
このデータからわかること
このデータには、member_rank のようなカテゴリ列、city のような文字列列、rating のような数値列が含まれています。さらに、NaN、大文字・小文字の違い、余分な空白も入っているため、value_counts() の基本だけでなく、実務でよくある問題も確認できます。
つまり、この1つのサンプルで、基本の件数集計、割合表示、欠損値の確認、表記ゆれの発見、数値データへの応用まで自然に学べるようになっています。
基本の使い方|件数を数える
まずは、もっとも基本的な使い方です。
print(df["member_rank"].value_counts())
| member_rank | count |
|---|---|
| Gold | 3 |
| Silver | 2 |
| Bronze | 1 |
| bronze | 1 |
| Silver | 1 |
この結果からわかること
この結果を見ると、Gold が3件で最も多く、次に Silver が2件あることがわかります。
一方で、Bronze と bronze、Silver と ” Silver ” が別々に集計されています。これは、value_counts() が見た目ではなく、実際の値をそのまま集計するためです。大文字・小文字の違いや前後の空白があると、別の値として数えられます。
また、この結果には NaN が表示されていません。これは、value_counts() がデフォルトでは欠損値を除外するためです。
ポイント
value_counts() は、件数の多い順に並びます デフォルトでは NaN は数えません 空白や大文字・小文字の違いも、別の値として集計されます
割合を表示する方法|normalize=True
件数だけでなく、全体に対する割合を見たいこともあります。その場合は normalize=True を指定します。
print(df["member_rank"].value_counts(normalize=True))
| member_rank | proportion |
|---|---|
| Gold | 0.375 |
| Silver | 0.250 |
| Bronze | 0.125 |
| bronze | 0.125 |
| Silver | 0.125 |
この結果からわかること
この結果では、Gold が全体の 37.5%、Silver が 25.0% を占めていることがわかります。
件数だけを見ると「Gold は3件」としかわかりませんが、割合を見ることで、全体の中でどれくらいの比率なのかを把握できます。
特に、データ件数が増えると、単純な件数だけでは比較しにくくなることがあります。そのため、カテゴリの偏りを確認したいときは、件数と割合の両方を見るのがおすすめです。
ポイント
0〜1 の小数で返ります 0.375 は 37.5% を意味します 件数よりも、全体に対する比率を比較しやすくなります 見やすくしたい場合は round() を組み合わせます。
print(df["member_rank"].value_counts(normalize=True).round(3))
| member_rank | proportion |
|---|---|
| Gold | 0.375 |
| Silver | 0.250 |
| Bronze | 0.125 |
| bronze | 0.125 |
| Silver | 0.125 |
パーセント表示にする方法
割合をパーセントで表示したい場合は、100をかけます。
print((df["member_rank"].value_counts(normalize=True) * 100).round(1))
| member_rank | proportion |
|---|---|
| Gold | 37.5 |
| Silver | 25.0 |
| Bronze | 12.5 |
| bronze | 12.5 |
| Silver | 12.5 |
% をつけて表示したい場合は、次のように書けます。
rate = (df["member_rank"].value_counts(normalize=True) * 100).round(1).astype(str) + "%"
print(rate)
| member_rank | proportion |
|---|---|
| Gold | 37.5% |
| Silver | 25.0% |
| Bronze | 12.5% |
| bronze | 12.5% |
| Silver | 12.5% |
この結果からわかること
割合をパーセントで表示すると、結果がかなり直感的になります。特に、レポートやブログ記事など、人に見せる前提の場面では 0.375 より 37.5% のほうが伝わりやすいです。
分析途中では小数のままでも問題ありませんが、説明用の資料ではパーセント表示のほうが親切です。
欠損値も数える方法|dropna=False
value_counts() は、デフォルトでは NaN を集計しません。
NaN も含めて数えたい場合は、dropna=False を指定します。
print(df["member_rank"].value_counts(dropna=False))
| member_rank | count |
|---|---|
| Gold | 3 |
| Silver | 2 |
| Bronze | 1 |
| NaN | 1 |
| bronze | 1 |
| Silver | 1 |
この結果からわかること
今度は NaN が1件あることが表示されました。つまり、この member_rank 列には欠損値が1つ含まれていると確認できます。
基本の value_counts() だけを見ると、欠損値が存在しないように見えることがあります。ですが、dropna=False を使えば、欠損値も含めた本当の分布を見ることができます。
ポイント
- dropna=False をつけると、欠損値も件数に含まれます
- データ品質の確認に便利です
- 前処理の前に、欠損値の有無をざっくり把握できます
欠損値を含めた割合を表示する方法
NaN も含めて割合を出したい場合は、normalize=True と dropna=False を組み合わせます。
print(df["member_rank"].value_counts(normalize=True, dropna=False).round(3))
| member_rank | proportion |
|---|---|
| Gold | 0.333 |
| Silver | 0.222 |
| Bronze | 0.111 |
| NaN | 0.111 |
| bronze | 0.111 |
| Silver | 0.111 |
この結果からわかること
この結果では、NaN が全体の約11.1%を占めていることがわかります。件数だけでなく割合でも確認できるため、欠損値の影響がどれくらい大きいかを判断しやすくなります。
たとえば、欠損値が1件だけなら大きな問題でないこともありますが、全体の3割、4割を占めるようなら、分析結果への影響は無視できません。割合で見ると、その重要度をより判断しやすくなります。
少ない順に並べたいとき|ascending=True
value_counts() はデフォルトで件数の多い順に並びます。少ない順にしたい場合は ascending=True を使います。
print(df["member_rank"].value_counts(dropna=False, ascending=True))
| member_rank | count |
|---|---|
| NaN | 1 |
| Bronze | 1 |
| Silver | 1 |
| bronze | 1 |
| Silver | 2 |
| Gold | 3 |
この結果からわかること
少ない順に並べると、件数の少ないカテゴリから確認できます。この例では、NaN、Bronze、bronze、” Silver ” がいずれも1件ずつであることがすぐにわかります。
多数派だけでなく、少数派や例外的な値を見つけたいときに便利です。入力ミスや珍しいカテゴリを探したいときは、降順より昇順のほうが見やすい場合があります。
値順に並べたいとき|sort_index()
value_counts() は件数順に並びます。値そのものの順番で見たいときは、sort_index() を組み合わせます。
print(df["member_rank"].value_counts(dropna=False).sort_index())
| member_rank | count |
|---|---|
| Silver | 1 |
| Bronze | 1 |
| Gold | 3 |
| Silver | 2 |
| bronze | 1 |
| NaN | 1 |
この結果からわかること
件数順ではなく、値そのものの順番で並べたいときに便利です。ただし、空白つきの ” Silver ” が先頭に来ていることからもわかるように、余分な空白があると並び順にも影響することがあります。
ここでも、表記ゆれや前処理の重要性が見えてきます。
よく使う書き方まとめ【比較表】
| やりたいこと | 書き方 |
|---|---|
| 件数を数える | df[“列名”].value_counts() |
| 割合を出す | df[“列名”].value_counts(normalize=True) |
| 欠損値も含める | df[“列名”].value_counts(dropna=False) |
| 欠損値込みで割合を出す | df[“列名”].value_counts(normalize=True, dropna=False) |
| 少ない順に並べる | df[“列名”].value_counts(ascending=True) |
| 値順に並べる | df[“列名”].value_counts().sort_index() |
| 件数でソートしない | df[“列名”].value_counts(sort=False) |
まずは次の3つを押さえておくと十分です。
- 件数を数える
- 割合を出す
- 欠損値も含める
そのうえで、並び順を変えたいときに ascending=True や sort_index() を使う、と覚えると整理しやすいです。
また、デフォルトの件数ソートが不要な場合は sort=False を使うこともできます。
value_counts() の結果を表として扱う方法
value_counts() の結果は Series です。そのため、そのままでも使えますが、表として扱いやすくしたい場合は reset_index() を使います。
result = df["member_rank"].value_counts(dropna=False).reset_index()
result.columns = ["member_rank", "count"]
print(result)
| member_rank | count |
|---|---|
| Gold | 3 |
| Silver | 2 |
| Bronze | 1 |
| NaN | 1 |
| bronze | 1 |
| Silver | 1 |
この結果からわかること
value_counts() の結果が、2列のDataFrameとして扱いやすい形になりました。これにより、あとで別の表と結合したり、CSVで保存したり、グラフ用データとして使ったりしやすくなります。
分析の途中ではSeriesのままでも十分ですが、あとで加工したいときはDataFrameにしておくと便利です。
件数と割合をまとめて表示する方法
件数と割合を一緒に見たい場合は、次のように書けます。
counts = df["member_rank"].value_counts(dropna=False)
rates = df["member_rank"].value_counts(normalize=True, dropna=False) * 100
summary = pd.DataFrame({
"count": counts,
"rate(%)": rates.round(1)
})
print(summary)
| member_rank | count | rate(%) |
|---|---|---|
| Gold | 3 | 33.3 |
| Silver | 2 | 22.2 |
| Bronze | 1 | 11.1 |
| NaN | 1 | 11.1 |
| bronze | 1 | 11.1 |
| Silver | 1 | 11.1 |
この結果からわかること
この表では、各カテゴリについて「何件あるか」と「全体の何%か」を同時に確認できます。たとえば、Gold は3件で 33.3%、Silver は2件で 22.2%、NaN は 11.1% です。
このように件数と割合をまとめて見ると、分布の全体像を一目で把握しやすくなります。ブログや資料に載せるときにも、この形式は非常に使いやすいです。
value_counts() は表記ゆれの発見にも便利
value_counts() は、データクリーニングの入口としても便利です。
たとえば city 列を見てみます。
print(df["city"].value_counts(dropna=False))
| city | count |
|---|---|
| Tokyo | 3 |
| Nagoya | 2 |
| Osaka | 1 |
| osaka | 1 |
| Tokyo | 1 |
| NaN | 1 |
この結果からわかること
この結果では、Tokyo が3件、Nagoya が2件となっていますが、同時に Osaka と osaka、Tokyo と Tokyo が別々に存在していることもわかります。
つまり、同じ意味の値が表記の違いによって分かれてしまっている状態です。このまま集計を進めると、本来まとめるべきカテゴリが分散し、正しい分布を把握しにくくなります。
このようなときは、文字列をそろえてから再集計します。
df["city_cleaned"] = df["city"].str.strip().str.lower()
print(df["city_cleaned"].value_counts(dropna=False))
| city_cleaned | count |
|---|---|
| tokyo | 4 |
| osaka | 2 |
| nagoya | 2 |
| NaN | 1 |
この結果からわかること
クリーニング後は、Tokyo と Tokyo が tokyo に統一され、Osaka と osaka も osaka にまとまりました。その結果、都市ごとの実際の件数がかなりわかりやすくなっています。
このように、value_counts() は単なる件数集計だけでなく、前処理の前後でデータが整ったかを確認する道具としても使えます。
ポイント
- 表記ゆれや入力ミスの発見に向いています
- 前処理の前後で比較すると、クリーニングの効果を確認しやすいです
数値データにも使える
value_counts() は文字列だけでなく、数値データにも使えます。
たとえば rating 列の件数を見てみます。
print(df["rating"].value_counts())
| rating | count |
|---|---|
| 4 | 4 |
| 5 | 3 |
| 3 | 2 |
この結果からわかること
この結果では、評価4が4件で最も多く、次に評価5が3件、評価3が2件あるとわかります。つまり、このデータでは極端に偏った分布ではなく、中間的な評価がやや多い傾向が見えます。
アンケートの回答、テストの点数、レビュー評価などでも同じように使えます。
value_counts() の結果はグラフ化にも使える
value_counts() の結果はSeriesなので、そのまま棒グラフに使えます。
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
df["member_rank"].value_counts(dropna=False).plot(kind="bar")
plt.xlabel("member_rank")
plt.ylabel("count")
plt.title("member_rank の件数集計")
plt.show()
この結果からわかること
棒グラフにすると、どのカテゴリが多いかを視覚的に確認しやすくなります。表だけでも十分ですが、カテゴリ数が多いときや他人に説明するときは、グラフのほうが伝わりやすいことがあります。
ただし、今回の記事の主役はあくまで value_counts() なので、可視化は「こういう使い方もできる」と押さえておく程度で十分です。
value_counts() と groupby().size() と count() の違い
| 書き方 | 主な用途 | 特徴 |
|---|---|---|
| value_counts() | 1列の値の出現回数を数える | 最も手軽でわかりやすい |
| groupby().size() | グループごとの件数を数える | 複数列の組み合わせ集計にも向く |
| count() | 欠損値を除いた件数を数える | 列ごとの非欠損件数を見るときに使う |
どう使い分ければよいか
まず、1列だけの分布確認なら value_counts() が最も簡単です。
たとえば「会員ランクごとの人数を知りたい」なら、value_counts() が最短です。
一方、複数列の組み合わせで件数を見たいときは groupby().size() が向いています。たとえば「都市ごと・会員ランクごとの件数を見たい」といった場面です。
また、count() は「値の種類ごとの件数」を数えるというより、欠損でないデータが何件あるかを見るときに使います。そのため、value_counts() と同じ用途だと思うと混乱しやすいです。
初心者向けの覚え方
- 1列の分布を見る → value_counts()
- 複数条件で件数を出す → groupby().size()
- 欠損を除いた件数を知る → count()
よくある使い方の例
- 会員ランクの分布確認
- アンケート回答の件数確認
- 都道府県別・カテゴリ別の件数確認
- 欠損値を含めたデータ品質チェック
- 表記ゆれや入力ミスの発見
つまり、value_counts() は分析の最初にデータの中身をざっくり把握するための定番メソッドと言えます。
大規模データでの考慮事項
value_counts() は便利ですが、ユニークな値が非常に多い列に使うと、結果が長くなりやすいです。
たとえば、ID列や自由入力の文字列列では、ほとんど同じ値が出てこないことがあります。その場合、集計しても見づらくなることがあります。
そんなときは、上位だけ確認する方法が便利です。
print(df[“member_rank”].value_counts(dropna=False).head())
この考え方のポイント
value_counts() はカテゴリ列にはとても向いていますが、ほぼすべて違う値が入っている列では、結果が長すぎて役立ちにくいことがあります。そのような場合は head() で上位だけを見る、あるいは別の列を集計対象にする、といった工夫が必要です。
よくある間違い
NaN が表示されないのはおかしいと思ってしまう
これはバグではありません。value_counts() はデフォルトで NaN を除外します。df[“member_rank”].value_counts(dropna=False)と書けば、NaN も数えられます。
割合が 0〜1 の小数で返ってきて戸惑う
normalize=True は割合を返しますが、50% ではなく 0.5 のように返ってきます。(df[“member_rank”].value_counts(normalize=True) * 100).round(1)のように書くと、見やすくなります。
表記ゆれに気づかず、そのまま集計してしまう
Silver と ” Silver “、Bronze と bronze のように、見た目は近くても別の値として集計されます。そのため、件数を見るときは、本当に同じカテゴリとして扱ってよいかを意識することが大切です。
ワンポイント
value_counts() は、head()、info()、describe() と並んで、データを読み込んだ直後に確認したい基本操作の1つです。
head() で先頭行を見る info() で型と欠損を見る value_counts() でカテゴリの分布を見る という流れで確認すると、データの全体像をかなりつかみやすくなります。
つまり、value_counts() は「あとで使う関数」ではなく、最初に使う確認用メソッドとして覚えておくと実務でも役立ちます。
まとめ
value_counts() は、列の値ごとの出現回数をすばやく集計できる便利なメソッドです。
基本の形はとてもシンプルです。
df[“列名”].value_counts() さらに、
- 割合を出したい → normalize=True
- 欠損値も含めたい → dropna=False
- 少ない順に並べたい → ascending=True を組み合わせることで、より実用的に使えます。
また、単なる件数集計だけでなく、
- カテゴリの偏り確認
- 欠損値の確認
- 表記ゆれの発見
- 可視化前の下準備
にも役立ちます。
Pandasでデータを読み込んだら、head() や info() とあわせて、ぜひ value_counts() も使ってみてください。
value_counts() とは何ですか?
Seriesに含まれる値ごとの出現回数を数えるメソッドです。1列のカテゴリ分布を確認するときによく使います。
割合を表示するにはどうすればよいですか?
normalize=True を指定します。
df[“member_rank”].value_counts(normalize=True)
欠損値も数えられますか?
はい。dropna=False を指定すると、NaN も件数に含められます。
df[“member_rank”].value_counts(dropna=False)
groupby().size() との違いは何ですか?
value_counts() は1列の出現回数を手軽に数えるのに向いています。
一方、groupby().size() は複数列の組み合わせ集計など、より柔軟な集計に向いています。
コメント