データ構造

pythonなどプログラミング言語では、ライブラリと呼ばれる誰かが作ったプログラムのまとまりをインポートすることで、その機能を使えるようになる。
pandasはpythonでは最も有名な多機能なデータ処理のライブラリ。
ライブラリはパッケージとも言う(厳密には違う意味かも)。プログラムはコード、モジュールなどとも言う。


In [2]:
import pandas as pd#pandasはpdとしてインポートすることが通例。

リストは複数の値をまとめて持つことができる基本的なデータ構造。


In [3]:
list_a = [3,5,9,2,5]
list_a


Out[3]:
[3, 5, 9, 2, 5]

数値以外でもリストとして持つことができる。文字列型(String型)は''または""で囲む。なお、上記リストの数値は整数型(int型)であり、数値には小数を表現できる浮動小数点数型(float型)がある。


In [4]:
list_b = ['b','r','g','y','k']
list_b


Out[4]:
['b', 'r', 'g', 'y', 'k']

1次元データ:Series

pandasには1次元のデータを扱うSeries型がある。


In [5]:
series_a = pd.Series(list_a)
series_a


Out[5]:
0    3
1    5
2    9
3    2
4    5
dtype: int64

Series型はインデックスを持つ1次元データである。デフォルトでは0から順に整数のインデックスが振られる。なお、pythonのインデックスは指定しない限りどの型でも1ではなく0から始まる。


In [6]:
series_a.index


Out[6]:
RangeIndex(start=0, stop=5, step=1)

In [7]:
series_a.values


Out[7]:
array([3, 5, 9, 2, 5])

Seriesの各要素をインデックスで取り出すことができる。


In [8]:
series_a[3]


Out[8]:
2

データの型はデータ処理をする上で、非常に重要。データ処理のエラーはデータの型によって起こりやすい。型エラーの際には、もしくは事前に、型を確認する。


In [9]:
type(series_a)


Out[9]:
pandas.core.series.Series

Seriesの各要素の型を調べるにはインデックスで指定する。


In [10]:
type(series_a[3])


Out[10]:
numpy.int64

pythonにはnumpyという数値処理を扱うライブラリがあり、pandasでもnumpyを使っている。numpyは専用の数値の型をもっている。
RangeIndexもpandasのRangeIndex型のオブジェクトである。


In [11]:
import numpy as np

他のシーケンスと同じように抽出することができる。printすると型をdtypeとして確認できる。


In [12]:
series_a[:3]


Out[12]:
0    3
1    5
2    9
dtype: int64

インデックスは名前をつけて指定することができる。


In [14]:
series_b = pd.Series(list_a,index=list_b)
series_b


Out[14]:
b    3
r    5
g    9
y    2
k    5
dtype: int64

Series自体に名前をつけることができる。デフォルトでは名前はない。


In [15]:
series_b = pd.Series(list_a,index=list_b,name='color')
series_b


Out[15]:
b    3
r    5
g    9
y    2
k    5
Name: color, dtype: int64

rangeインデックスと同じようにインデックスで抽出できる。


In [16]:
series_b['g']


Out[16]:
9

In [17]:
series_b['r':'y']


Out[17]:
r    5
g    9
y    2
Name: color, dtype: int64

インデックスに名前をつけた場合もrangeインデックスでの抽出も可能。


In [18]:
series_b[2]


Out[18]:
9

インデックスを混ぜることはできない。


In [19]:
series_b[1:'y']


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-19-25183638cdef> in <module>()
----> 1 series_b[1:'y']

/anaconda/lib/python3.6/site-packages/pandas/core/series.py in __getitem__(self, key)
    642             key = check_bool_indexer(self.index, key)
    643 
--> 644         return self._get_with(key)
    645 
    646     def _get_with(self, key):

/anaconda/lib/python3.6/site-packages/pandas/core/series.py in _get_with(self, key)
    647         # other: fancy integer or otherwise
    648         if isinstance(key, slice):
--> 649             indexer = self.index._convert_slice_indexer(key, kind='getitem')
    650             return self._get_values(indexer)
    651         elif isinstance(key, ABCDataFrame):

/anaconda/lib/python3.6/site-packages/pandas/indexes/base.py in _convert_slice_indexer(self, key, kind)
   1236         else:
   1237             try:
-> 1238                 indexer = self.slice_indexer(start, stop, step, kind=kind)
   1239             except Exception:
   1240                 if is_index_slice:

/anaconda/lib/python3.6/site-packages/pandas/indexes/base.py in slice_indexer(self, start, end, step, kind)
   2995         """
   2996         start_slice, end_slice = self.slice_locs(start, end, step=step,
-> 2997                                                  kind=kind)
   2998 
   2999         # return a slice

/anaconda/lib/python3.6/site-packages/pandas/indexes/base.py in slice_locs(self, start, end, step, kind)
   3174         start_slice = None
   3175         if start is not None:
-> 3176             start_slice = self.get_slice_bound(start, 'left', kind)
   3177         if start_slice is None:
   3178             start_slice = 0

/anaconda/lib/python3.6/site-packages/pandas/indexes/base.py in get_slice_bound(self, label, side, kind)
   3113         # For datetime indices label may be a string that has to be converted
   3114         # to datetime boundary according to its resolution.
-> 3115         label = self._maybe_cast_slice_bound(label, side, kind)
   3116 
   3117         # we need to look up the label

/anaconda/lib/python3.6/site-packages/pandas/indexes/base.py in _maybe_cast_slice_bound(self, label, side, kind)
   3071         # this is rejected (generally .loc gets you here)
   3072         elif is_integer(label):
-> 3073             self._invalid_indexer('slice', label)
   3074 
   3075         return label

/anaconda/lib/python3.6/site-packages/pandas/indexes/base.py in _invalid_indexer(self, form, key)
   1282                         "indexers [{key}] of {kind}".format(
   1283                             form=form, klass=type(self), key=key,
-> 1284                             kind=type(key)))
   1285 
   1286     def get_duplicates(self):

TypeError: cannot do slice indexing on <class 'pandas.indexes.base.Index'> with these indexers [1] of <class 'int'>

*に対し、listは同じリストが連結され、Seriesはvaluesが2倍される。


In [8]:
print(list_a * 2)
print(series_a * 2)


[3, 5, 9, 2, 5, 3, 5, 9, 2, 5]
0     6
1    10
2    18
3     4
4    10
dtype: int64

In [11]:
print(3 in list_a)
print(3 in series_a)


True
True

ユニーク(一意な値の確認)


In [27]:
series_a.unique()


Out[27]:
array([3, 5, 9, 2])

2次元データ:DataFrame

DataFrame型はデータ処理で最もよく使うオブジェクト。


In [20]:
lists = [list_a,list_b]
lists


Out[20]:
[[3, 5, 9, 2, 5], ['b', 'r', 'g', 'y', 'k']]

In [21]:
pd.DataFrame(lists)


Out[21]:
0 1 2 3 4
0 3 5 9 2 5
1 b r g y k

データフレームの行と列は次のように呼ばれる。

  • 列、column、カラム、フィールド、属性
  • 行、row、ロー、レコード
    一般に行は各個人やサンプルなどであり、列は性別、年齢などの属性を表す形式でテーブルが作成される。

In [22]:
df1 = pd.DataFrame(lists)
df1 = df1.T#転置
print(df1)


   0  1
0  3  b
1  5  r
2  9  g
3  2  y
4  5  k

列名や行名を調べる。


In [23]:
print(df1.columns)
print(df1.index)


RangeIndex(start=0, stop=2, step=1)
RangeIndex(start=0, stop=5, step=1)

列名、行名をつける。


In [24]:
df1.columns = ['数値','色']
df1.index = range(1,6)
df1


Out[24]:
数値
1 3 b
2 5 r
3 9 g
4 2 y
5 5 k

In [26]:
print(range(1,6))
print(type(range(1,6)))
print(list(range(1,6)))
print(range(5))
print(list(range(5)))


range(1, 6)
<class 'range'>
[1, 2, 3, 4, 5]
range(0, 5)
[0, 1, 2, 3, 4]

DataFrameの詳細は別の.ipynbで。