情報・内容の取得
データの概観
基本的なパラメーターの取得
DataFrameの生成
要素の操作
列の操作
行の操作
DataFrameで直接行を指定して参照
DataFrame
で直接行番号を指定する場合はスライスで指定する。1行取り出す場合でもdf[col:col+1]
のようにスライスにしなければならない。
maskによる行の抽出
DataFrameの特定列に対する条件式は、その条件に応じたTrue/Falseを要素とするSeriesオブジェクトを返す。
そのSeriesオブジェクトをDataFrameの引数とすると、Trueに対応する行だけが抽出される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
names = ["Austin", "Bill", "Charie", "Dick"] ages = np.array([38, 25, 52, 18]) data_frame = pd.DataFrame({'name': names, 'age': ages}) print("source data frame:\n{}".format(data_frame)) mask = data_frame['age'] > 30 print("mask data frame:\n{}".format(mask)) print("masked data frame:\n{}".format(data_frame[mask])) # source data frame: # name age # 0 Austin 38 # 1 Bill 25 # 2 Charie 52 # 3 Dick 18 # mask data frame: # 0 True # 1 False # 2 True # 3 False # Name: age, dtype: bool # masked data frame: # name age # 0 Austin 38 # 2 Charie 52 |
これをまとめて次のようにも書ける。
1 2 3 4 5 |
print(data_frame[data_frame['age'] > 30]) # name age # 0 Austin 38 # 2 Charie 52 |
抽出結果の特定の列を参照可能。結果はSeriesオブジェクト。
1 2 3 4 5 |
print(data_frame[data_frame['age'] > 30]['name']) # 0 Austin # 2 Charie # Name: name, dtype: object |
queryによる行の抽出
DataFrameのquery()メソッドでも行を抽出できる。
1 2 3 4 5 6 7 8 9 10 11 |
print(data_frame) print(data_frame.query('age > 30')) # name age # 0 Austin 38 # 1 Bill 25 # 2 Charie 52 # 3 Dick 18 # name age # 0 Austin 38 # 2 Charie 52 |
抽出結果から特定の列を参照可能。結果はSeriesオブジェクト。
1 2 3 4 5 |
print(data_frame.query('age > 30')['name']) # 0 Austin # 2 Charie # Name: name, dtype: object |
行の追加
1行追加する場合
1行追加する場合、locで新たな行インデックスを指定して内容を与える。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import numpy as np from pandas import DataFrame source = np.array([ ["zero", 0], ["one", 1], ["two", 2] ]) df = DataFrame(source, columns=['number', 'numeric']) print(df) # number numeric # 0 zero 0 # 1 one 1 # 2 two 2 df.loc[3] = ["three", 3] print(df) # number numeric # 0 zero 0 # 1 one 1 # 2 two 2 # 3 three 3 |
複数行追加する場合
複数行(=配列)を追加する場合、その配列をDataFrame
オブジェクトとしてからappend()
メソッドを使う。ただし単純に追加すると、新たな行・列として拡張されてしまう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
source = np.array([ ["zero", 0], ["one", 1], ["two", 2] ]) df = DataFrame(source, columns=['number', 'numeric']) print(df) to_add = np.array([ ["three", 3], ["four", 4] ]) df_to_add = DataFrame(to_add) print(df.append(df_to_add)) # number numeric 0 1 # 0 zero 0 NaN NaN # 1 one 1 NaN NaN # 2 two 2 NaN NaN # 0 NaN NaN three 3 # 1 NaN NaN four 4 |
これを回避するためには、追加する行の列名をcolumns
で明示する。ただしこの段階では、追加された行のインデックスが連続していない。
1 2 3 4 5 6 7 8 9 |
df_to_add = DataFrame(to_add, columns=['number', 'numeric']) print(df.append(df_to_add)) # number numeric # 0 zero 0 # 1 one 1 # 2 two 2 # 0 three 3 # 1 four 4 |
インデックスを連続させるためには、ignore_index=True
を指定する。
1 2 3 4 5 6 7 8 9 |
df_new = df.append(df_to_add, ignore_index=True) print(df_new) # number numeric # 0 zero 0 # 1 one 1 # 2 two 2 # 3 three 3 # 4 four 4 |
DataFrameの結合
cocatメソッド~縦方向の結合
concat()
メソッドは複数のDataFrame
を縦に結合した結果を返す。列の構成が同じDataFrame
オブジェクトをリスト化して与える。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import pandas as pd df1 = pd.DataFrame([[10, 11, 12], [20, 21, 22]]) df2 = pd.DataFrame([[30, 31, 32], [40, 41, 42]]) df = pd.concat([df1, df2]) print(df) # 0 1 2 # 0 10 11 12 # 1 20 21 22 # 0 30 31 32 # 1 40 41 42 |
列数が異なるDataFrame
を結合すると、余った要素にはNaN
がセットされる。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import pandas as pd df1 = pd.DataFrame([[10, 11], [20, 21]]) df2 = pd.DataFrame([[30, 31, 32], [40, 41, 42]]) df = pd.concat([df1, df2]) print(df) # 0 1 2 # 0 10 11 NaN # 1 20 21 NaN # 0 30 31 32.0 # 1 40 41 42.0 |
joinメソッド~横方向の結合
join()
メソッドは元のDataFrame
に引数のDataFrame
を結合した結果を返す。結合は行のインデックスに着目して実行され、インデックスが同じデータは同じ行の列方向に追加される。すなわち、同じ行数で異なる列のDataFrame
を結合するのに適している。
破壊的な処理ではなく、元のDataFrame
はそのままで新しいDataFrame
が生成される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import pandas as pd data1 = [ [1, 4], [2, 5], [3, 6] ] data2 = [ [7, 10], [8, 11], [9, 12] ] df1 = pd.DataFrame(data1, columns=['1', '2']) df2 = pd.DataFrame(data2, columns=['3', '4']) print(df1) # 1 2 # 0 1 4 # 1 2 5 # 2 3 6 print(df2) # 3 4 # 0 7 10 # 1 8 11 # 2 9 12 print(df1.join(df2)) # 1 2 3 4 # 0 1 4 7 10 # 1 2 5 8 11 # 2 3 6 9 12 |
この例では2つのDataFrame
の行が一致しており、列が異なるので、横方向に結合されている。同じ列名が存在する場合はValueErrorとなる。
3つ以上のDataFrame
を結合したい場合(引数に2つ以上のDataFrame
を指定したい場合)は、それら複数のDataFrame
をタプルかリストでまとめて指定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
data3 = [[13], [14], [15]] df3 = pd.DataFrame(data3, columns=['5']) print(df3) # 5 # 0 13 # 1 14 # 2 15 print(df1.join([df2, df3])) # 1 2 3 4 5 # 0 1 4 7 10 13 # 1 2 5 8 11 14 # 2 3 6 9 12 15 |
合計の計算と合計欄
以下の配列を使う。
1 2 3 4 5 6 7 8 9 10 |
import numpy as np import pandas as pd df = pd.DataFrame(np.arange(9).reshape(3, 3)) print(df) # 0 1 2 # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 |
sum()
メソッドはSeries
オブジェクトを返す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
sums_in_col = df.sum() sums_in_row = df.sum(axis=1) print("sums in column") print(sums_in_col) print("sums in row") print(sums_in_row) # sums in column # 0 9 # 1 12 # 2 15 # dtype: int64 # sums in row # 0 3 # 1 12 # 2 21 # dtype: int64 |
合計欄としてDataFrameに追加する場合、行/列いずれかの合計を計算して追加し、その上で他方の合計を計算して追加すると、総計まで計算できる。
行の追加はlocプロパティーを通じて、列の追加は列名を指定して行う。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
sums_in_col = df.sum() df.loc['Total'] = sums_in_col print(df) # 0 1 2 # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 # Total 9 12 15 sums_in_row = df.sum(axis=1) df['Total'] = sums_in_row print(df) # 0 1 2 Total # 0 0 1 2 3 # 1 3 4 5 12 # 2 6 7 8 21 # Total 9 12 15 36 |
ソート
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
sums_in_col = df.sum() sums_in_row = df.sum(axis=1) print("sums in column") print(sums_in_col) print("sums in row") print(sums_in_row) # sums in column # 0 9 # 1 12 # 2 15 # dtype: int64 # sums in row # 0 3 # 1 12 # 2 21 # dtype: int64 |
以下のデータを使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import numpy as np from pandas import DataFrame lst = np.array([ ["Alex", "DC", 44, 168], ["Bert", "NY", 18, 176], ["Carl", "CA", 26, 175], ["Daryl", "DC", 32, 182], ["Eddy", "CA", 58, 192] ]) df = DataFrame(lst, columns=["name", "state", "age", "height"]) print(df) # name state age height # 0 Alex DC 44 168 # 1 Bert NY 18 176 # 2 Carl CA 26 175 # 3 Daryl DC 32 182 # 4 Eddy CA 58 192 |
sort_values()
~列名を指定してソート
デフォルトは昇順。元のオブジェクトは変更されず、ソート後のDataFrameオブジェクトが生成されて返される。
1 2 3 4 5 6 7 8 9 |
df_sort_age = df.sort_values("age") print(df_sort_age) # name state age height # 1 Bert NY 18 176 # 2 Carl CA 26 175 # 3 Daryl DC 32 182 # 0 Alex DC 44 168 # 4 Eddy CA 58 192 |
ascending
パラメーター
ascending=False
を指定すると降順でソート。
1 2 3 4 5 6 7 8 |
print(df.sort_values("age", ascending=False)) # name state age height # 4 Eddy CA 58 192 # 0 Alex DC 44 168 # 3 Daryl DC 32 182 # 2 Carl CA 26 175 # 1 Bert NY 18 176 |
reset_index()
~インデックスの降り直し
ソート後にインデックスを振りなおす場合、reset_index()
メソッドを使う。このメソッドも元のオブジェクトを変更しない。
1 2 3 4 5 6 7 8 |
print(df_sort_age.reset_index()) index name state age height # 0 1 Bert NY 18 176 # 1 2 Carl CA 26 175 # 2 3 Daryl DC 32 182 # 3 0 Alex DC 44 168 # 4 4 Eddy CA 58 192 |
降りなおした後のインデックスで元のインデックスを上書きする場合は、drop=True
を指定。
1 2 3 4 5 6 7 8 |
print(df_sort_age.reset_index(drop=True)) # name state age height # 0 Bert NY 18 176 # 1 Carl CA 26 175 # 2 Daryl DC 32 182 # 3 Alex DC 44 168 # 4 Eddy CA 58 192 |
複数列によるソート
複数列を指定してソートする場合、ソートの優先順にリストで指定。ascending
パラメーターに同じ要素数のTrue/False
リストを与えて、列ごとの昇順/降順を指定可能。
1 2 3 4 5 6 7 8 |
print(df.sort_values(["state", "height"], ascending=[True, False])) # name state age height # 4 Eddy CA 58 192 # 2 Carl CA 26 175 # 3 Daryl DC 32 182 # 0 Alex DC 44 168 # 1 Bert NY 18 176 |
axisの方向
各種演算・処理の引数でaxisを設定するときの、行方向・列方向がまぎらわしいので整理。
DataFrameの設定
列のインデックス設定
set_index()
メソッドにより、第1引数keysで指定した列をインデックスに設定される。
表示行数・列数の設定
表示行数・列数の省略
行数・列数が多いDataFrameを表示させると、途中を省略して表示する。デフォルトで行数は60行を超えると省略され、列数は画面幅に応じて調整される。以下のコードは、pandasのオプションでdisplay.max_rows
とdisplay.max_columns
も表示させている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import numpy as np import pandas as pd import string n_rows = 61 n_columns = 20 data = np.array([[r * 10 + c for c in range(n_columns)] for r in range(n_rows)]) column_names = list(string.ascii_letters)[26 : 26 + n_columns] df = pd.DataFrame(data, columns=column_names) print(df) print("max rows:{}".format(pd.options.display.max_rows)) print("max_cols:{}".format(pd.options.display.max_columns)) # A B C D E F G ... N O P Q R S T # 0 0 1 2 3 4 5 6 ... 13 14 15 16 17 18 19 # 1 10 11 12 13 14 15 16 ... 23 24 25 26 27 28 29 # 2 20 21 22 23 24 25 26 ... 33 34 35 36 37 38 39 # 3 30 31 32 33 34 35 36 ... 43 44 45 46 47 48 49 # 4 40 41 42 43 44 45 46 ... 53 54 55 56 57 58 59 # .. ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... # 56 560 561 562 563 564 565 566 ... 573 574 575 576 577 578 579 # 57 570 571 572 573 574 575 576 ... 583 584 585 586 587 588 589 # 58 580 581 582 583 584 585 586 ... 593 594 595 596 597 598 599 # 59 590 591 592 593 594 595 596 ... 603 604 605 606 607 608 609 # 60 600 601 602 603 604 605 606 ... 613 614 615 616 617 618 619 # # [61 rows x 20 columns] # max rows:60 # max_cols:0 |
この場合、行数に61行をしているので行表示は省略され、列数はコンソールの幅に応じて省略されている(コンソールの幅を変えて実行すると、その幅に応じて納めようと省略される)。
表示行数の設定
表示させる最大行数を変更するには、pandas.set_option()
でdisplay.max_rows
属性を設定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import numpy as np import pandas as pd import string n_rows = 100 n_columns = 20 data = np.array([[r * 10 + c for c in range(n_columns)] for r in range(n_rows)]) column_names = list(string.ascii_letters)[26 : 26 + n_columns] df = pd.DataFrame(data, columns=column_names) pd.set_option('display.max_rows', 100) print(df) # A B C D E F G ... N O P Q R S T # 0 0 1 2 3 4 5 6 ... 13 14 15 16 17 18 19 # 1 10 11 12 13 14 15 16 ... 23 24 25 26 27 28 29 # 2 20 21 22 23 24 25 26 ... 33 34 35 36 37 38 39 # 3 30 31 32 33 34 35 36 ... 43 44 45 46 47 48 49 # 4 40 41 42 43 44 45 46 ... 53 54 55 56 57 58 59 # ・・・この間の全ての行が表示される・・・ # 95 950 951 952 953 954 955 956 ... 963 964 965 966 967 968 969 # 96 960 961 962 963 964 965 966 ... 973 974 975 976 977 978 979 # 97 970 971 972 973 974 975 976 ... 983 984 985 986 987 988 989 # 98 980 981 982 983 984 985 986 ... 993 994 995 996 997 998 999 # 99 990 991 992 993 994 995 996 ... 1003 1004 1005 1006 1007 1008 1009 [100 rows x 20 columns] |
表示列数の設定
表示させる最大列数を設定するには、pandas.set_option()
でdisplay.max_columns
属性を設定する。以下の例では20列すべてを表示させていて、コンソールの幅に収まらない列は表単位で改行されている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import numpy as np import pandas as pd import string n_rows = 100 n_columns = 20 data = np.array([[r * 10 + c for c in range(n_columns)] for r in range(n_rows)]) column_names = list(string.ascii_letters)[26 : 26 + n_columns] df = pd.DataFrame(data, columns=column_names) pd.set_option('display.max_columns', 20) print(df) # A B C D E F G H I J K L M N \ # 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 # 1 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # 2 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # 3 30 31 32 33 34 35 36 37 38 39 40 41 42 43 # 4 40 41 42 43 44 45 46 47 48 49 50 51 52 53 # .. ... ... ... ... ... ... ... ... ... ... ... ... ... ... # 95 950 951 952 953 954 955 956 957 958 959 960 961 962 963 # 96 960 961 962 963 964 965 966 967 968 969 970 971 972 973 # 97 970 971 972 973 974 975 976 977 978 979 980 981 982 983 # 98 980 981 982 983 984 985 986 987 988 989 990 991 992 993 # 99 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 # # O P Q R S T # 0 14 15 16 17 18 19 # 1 24 25 26 27 28 29 # 2 34 35 36 37 38 39 # 3 44 45 46 47 48 49 # 4 54 55 56 57 58 59 # .. ... ... ... ... ... ... # 95 964 965 966 967 968 969 # 96 974 975 976 977 978 979 # 97 984 985 986 987 988 989 # 98 994 995 996 997 998 999 # 99 1004 1005 1006 1007 1008 1009 # # [100 rows x 20 columns] |
ファイルの読み込み
CSVファイル
DataFrameにCSVファイルの読み込みには、pandas.read_csv()
を使う。
- pandas.read_csv(path)
path
は読み込むCSVのパス
ヘッダー付きCSVファイル
たとえば、以下のようなヘッダー付きのCSVファイル(ex_basic_w_header.csv)を考える。
1 2 3 4 |
name,age Austine,25 Bill,16 Charly,51 |
このファイルが実行ファイルと同じディレクトリにある場合、以下のように__file__
を使って読み込むとよい。
データには自動的にインデックス番号が付加される。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_w_header.csv") df = pd.read_csv(path) print(df) # name age # 0 Austine 25 # 1 Bill 16 # 2 Charly 51 |
ヘッダー無しCSVファイル
以下のようなヘッダーがないファイルの場合。
1 2 3 |
Austine,25 Bill,16 Charly,51 |
そのまま読み込んでしまうと1行目がヘッダーと解釈されてしまう。
1 2 3 4 5 6 7 8 9 10 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_wo_header.csv") df = pd.read_csv(path) print(df) # Austine 25 # 0 Bill 16 # 1 Charly 51 |
引数にheader=None
を指定すると1行目からデータとして読み込み、列名には番号が振られる。
1 2 3 4 5 6 7 8 9 10 11 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_wo_header.csv") df = pd.read_csv(path, header=None) print(df) # 0 1 # 0 Austine 25 # 1 Bill 16 # 2 Charly 51 |
引数としてnames=(列名1, 列名2, ...)
を指定すると、ヘッダー無しとして読み込まれ、列名がセットされる。
1 2 3 4 5 6 7 8 9 10 11 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_wo_header.csv") df = pd.read_csv(path, names=("name", "age")) print(df) # name age # 0 Austine 25 # 1 Bill 16 # 2 Charly 51 |
行のスキップ
以下のように、先頭から何行か読み飛ばしたいファイルの時。
1 2 3 4 5 6 |
File: employees lest Date: 2020/04/01 name,age Austine,25 Bill,16 Charly,51 |
引数にskiprows
でスキップする行数を指定する。このとき、最初の行はヘッダーとして解釈される。
1 2 3 4 5 6 7 8 9 10 11 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_skiprows.csv") df = pd.read_csv(path, skiprows=2) print(df) # name age # 0 Austine 25 # 1 Bill 16 # 2 Charly 51 |
ヘッダー行の指定
ヘッダー行を含むファイルでヘッダーの開始行を指定したいときはheader
で開始位置を指定する。指定したヘッダーより前の行は無視される。
1 2 3 4 5 6 7 8 9 10 11 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_skiprows.csv") df = pd.read_csv(path, header=2) print(df) # name age # 0 Austine 25 # 1 Bill 16 # 2 Charly 51 |
インデックス列の指定
以下のファイルは通し番号付きで、番号には列名がない(1行目の1列目が空)。
1 2 3 4 |
,order,name,age 1, first, Austine,25 2, second, Bill,16 3, third, Charly,51 |
これをそのままデータフレームに読み込むと、1列目もデータと解釈されてインデックスが自動生成される。
1 2 3 4 5 6 7 8 9 10 11 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_skipcols.csv") df = pd.read_csv(path) print(df) # Unnamed: 0 order name age # 0 1 first Austine 25 # 1 2 second Bill 16 # 2 3 third Charly 51 |
引数にindex_col=0
を指定すると、その列がインデックスとして認識される。
1 2 3 4 5 6 7 8 9 10 11 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_skipcols.csv") df = pd.read_csv(path, index_col=0) print(df) # order name age # 1 first Austine 25 # 2 second Bill 16 # 3 third Charly 51 |
index_colを1以上の値にすると、それ以前の列は読み込まれない。ただし指定した列に列名が定義されていると、それもデータとみなされてしまう。
1 2 3 4 5 6 7 8 9 10 11 12 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_skipcols.csv") df = pd.read_csv(path, index_col=1) print(df) # Unnamed: 0 name age # order # first 1 Austine 25 # second 2 Bill 16 # third 3 Charly 51 |
日本語
日本語などマルチバイトの文字を含む場合、対応する文字コードを指定する。
1 2 3 4 5 6 7 8 9 10 11 |
import os import pandas as pd path = os.path.join(os.path.dirname(__file__), "ex_basic_jp.csv") df = pd.read_csv(path, encoding='SHIFT-JIS') print(df) # 名前 年齢 # 0 井上 25 # 1 田中 44 # 2 武藤 16 |
One-hot-encoding
DataFrameのget_dummies()
メソッドは、属性データをone-hotの形にエンコードしてくれる。
Tips – 注意点など
配列で生成しない方がいい
コード上で簡単なDataFrameを生成するとき、配列で数値と文字列を混在させるとトラブルになる。
DataFrameの行追加の速さ
DataFrameに行を追加する場合、基本的にはリストに変換してリストの状態で行を追加し、それをDataFrameに変換するのが最も速い。いくつかの方法による速さの違いはこちら。
行単位/列単位の合計・率の計算
DataFrameオブジェクトの行単位/列単位の合計や、それらを使った率の計算方法。