🐼

初めての人がわかった気になれるpandasの使い方

2021/08/05に公開

僕自身普段はGo言語をよく書いていてPython自体あんまりやらないので、pandasもほぼ使ったことなかったです。最近、pandasを使わざる負えない状況になり、ちょっと触りました。

pandasはものすごく便利で高機能だなと感じました。ただ、高機能すぎて、めっちゃ詳しく紹介してくれてる記事はいっぱいあるんですが、僕の知りたいのそこじゃない状態になってしまったので、最低限これだけわかったらpandasの基本を理解したといえるんじゃないかなという切り口でまとめました。

対象の読者

  • pandas初めて
  • pandasのデータ構造がわからない
  • pythonはなんとなく書ける

pandasのデータ構造は2種類ある

pandasのデータ構造には、DataFrameというテーブル(列と行)を表現するのデータ構造とSeriesという1列or1行だけを表現するデータ構造の2種類があります。

DataFrame

行と列が存在するいわゆるテーブルのようなデータ構造です。pandasといえばほとんどこのデータ構造を扱います。(公式ドキュメント

name height birthdate
a tanaka 160 1990-01-01
b yamada 170 1980-02-02
c kato 180 1970-03-03

各列には列名が付与されています。
一番左の列はインデックスといい、行番号のような存在です。インデックスにも列名を付与することもできますし、インデックスを複数列指定することもできます。インデックスは、数値、文字列、日時など様々なデータを利用することが可能です。

Series

DataFrameとは違い、1列のみ、もしくは1行のみを表現するデータ構造です。(公式ドキュメント

weight
a 53
b 67
c 83

1列だけですが、インデックスはあります。DataFrameと同じように複数列のインデックスを持つこともできますし、インデックスとしてまた数値、文字列、日時など様々なデータを利用することが可能です。また、列名はついていたり、ついてなかったりします。

DataFrameとSeriesの関係性と注意点

DataFrameは複数のSeriesの集まりによって構成されています。

僕の場合、Series型の存在を知らないときに、とあるライブラリでSeries型のデータが返ってきたので困惑しました。

1つだけのSeries型のデータでもDataFrameに変換することができます。ビギナーはSeries型のハンドリングを覚えるがめんどくさいと思うので、Series型のデータは迷わずDataFrame型に変換するとよいのではないかと思います。そうすれば、扱うのはDataFrame型だけに統一できるのでビギナーにとっては扱いやすくなるのかなと思います。

変換する方法は簡単で、series型のデータを.to_frame()するだけです。(公式ドキュメント

Series型のデータは速攻でDataFrame型のデータに変換しますので、この記事ではDataFrame型に対する操作についてのみ紹介していきます。

DataFrameの使い方

新しいDataFrameを作る

df = pd.DataFrame(
    [
        ['tanaka',160,datetime(1990, 1, 1)],
        ['yamada',170,datetime(1980, 2, 2)],
        ['kato',180,datetime(1970, 3, 3)]
    ],
    index=['a','b','c'],
    columns=['name','height','birthdate']
)

DataFrameの作り方は様々な方法があるので、こちらはDataFrameの作り方の1例です。この例では行ごとにデータを定義してますが、列ごとにデータを定義することもできますし、csvデータを読み込んでもいいですし、indexやcolumnsを指定しなくてもよいです。(公式ドキュメント

indexは指定しない場合、0,1,2...と自動的に連番になります。

DataFrameの中身をデバッグする

print(df)

printするだけです。データ量が多い時は、先頭の数行と末尾の数行を出しくれて、index、columns、レコード数などを以下のように表示してくれます。

                  Open        High         Low       Close   Adj Close   Volume
Date                                                                           
1966-07-05    0.000000    0.273663    0.267490    0.269547    0.124835   388800
1966-07-06    0.000000    0.283951    0.267490    0.283951    0.131506   692550
1966-07-07    0.000000    0.291152    0.271605    0.273663    0.126741  1858950
1966-07-08    0.000000    0.276749    0.267490    0.276749    0.128171  1239300
1966-07-11    0.000000    0.283951    0.272634    0.275720    0.127694   656100
...                ...         ...         ...         ...         ...      ...
2021-07-29  243.320007  245.199997  242.979996  244.020004  244.020004  2572300
2021-07-30  243.850006  245.410004  242.210007  242.710007  242.710007  2336800
2021-08-02  244.240005  244.679993  239.690002  240.100006  240.100006  2693900
2021-08-03  239.559998  239.949997  235.250000  236.949997  236.949997  3299300
2021-08-04  236.449997  236.600006  233.050003  234.830002  234.830002  2240000

[13866 rows x 6 columns]

DataFrameかSeriesか確認する

print(type(df))

DataFrameだった場合 -> <class 'pandas.core.frame.DataFrame'>
Seriesだった場合 -> <class 'pandas.core.series.Series'>
と出力されます。

SeriesをDataFrameに変換する

.to_frame()してあげるだけです。(公式ドキュメント

ser = pd.Series(
    [53, 67, 83],
    index=['a','b','c'],
    name="weight"
)
df = ser.to_frame()

DataFrameからindexの一覧を取り出す

df.index

DataFrameからcolumnの一覧を取り出す

df.columns

DataFrameから行を取り出す

行を取り出すとSeriesオブジェクトを取得します。

df.loc['index名']

DataFrameから条件を指定して複数行を取り出す

df.loc[df['height'] > 165]

DataFrameから値を取り出す

df.loc['index名', 'column名']

DataFrameを行ごとにループする

for index, row in df.iterrows():
	print(index) # indexの値を出力する
	print(row['column名']) # column名で値を取得できる

DataFrameのデータを更新する

indexとcolumnを指定してデータを更新できます。

df.loc['index名', 'colume名'] = "sato"

条件を指定して更新したい場合は下のようにできます。

df.loc[df['height'] > 165, 'name'] = "sato"

DataFrameに行を追加する

index名を指定して、値を配列として代入すると行を追加できます。配列の要素数が列数と一致する必要があります

df.loc['index名'] = ['sato',185,datetime(1960, 3, 3)]

indexを指定してないdataFrameだった場合、indexは0,1,2...と連番になっているのでlen(df)でDataFrameの行数を取得するのがよいでしょう。

df.loc[len(df)] = ['sato',185,datetime(1960, 3, 3)]

DataFrameに列を追加する

column名を指定して、値を配列を代入すると列を追加できます。配列の要素数が行数と一致する必要があります

df['column名'] = [55,65,75]

DataFrameの行を削除する

df.drop('index名')

DataFrameの列を削除する

drop()の引数にaxix=1を追加すると行を削除できます。

df.drop('column名', axis=1)

csvファイルをDataFrameとして読み込む

df = pd.read_csv('ファイルパス')

カラム名はcsvにヘッダーカラムがあれば、勝手に読み込んでくれます。他にも細かいオプションでカラム名を指定したり、何行かスキップして読み込んだりできます。(公式ドキュメント

csvファイルとして出力する

df.to_csv('ファイルパス')

たいていの場合はこれで良いと思います。オプションで細かい設定もできます。(公式ドキュメント

終わりに

pandasのデータ構造とDataFrameに対する一通りの処理をまとめました。これだけ知っていれば、それなりpandasを使ってデータを見たりいじったりできるかと思います。僕はここにあること以外のことは何も知りませんでしたが、pandas使ってデータをいじることはできました!

pandasはすごく高機能なので、同じ処理を様々な方法を用いて実現することができますし、いろんなオプションを駆使することでかゆいところまで手が届くように作られています。ここで紹介したのは、様々なやり方のうちの一例でしかありません。
細かなことは公式ドキュメントにありますので、都度必要なときに参考にするのがよさそうです。また、Googleで検索すれば、細かなことを紹介してくれている記事は日本語でも英語でもたくさんあるので困ることはなさそうです。

Discussion