9
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

馬鹿の一つ覚え: pandas

Last updated at Posted at 2017-11-01

最初に

import pandas
f = [None] * 8
f[0] = pandas.DataFrame(((0, 1), (2, 3)))

ここではデータフレームを複数格納するためのリストfを用意します。

テキストファイルを読み込み、DataFrame構造を確認する

f[0] = pandas.read_csv('data_1.tsv', sep = "\t", index_col = 0)
    # 1行目にheader、1列目にindexがあるタブ区切りファイル
print(f[0])    # DataFrame全体を表示
print(type(f[0]))    # pandas.core.frame.DataFrame
print(f[0].columns)    # 1行目に書かれていたheader(列名)を取得
print(f[0].index)    # 1列目に書かれていたindex(行名)を取得
print(f[0].info())    # 各列のデータ型を確認
print(len(f[0]))    # 行数を取得 (headerは除く)
print(len(f[0].columns))    # 列数を取得 (indexは除く)
print(f[0].shape)    # 行数と列数を取得 (headerやindexは除く)
print(f[0].head(4))    # 先頭4行を表示
print(f[0].tail(4))    # 末尾4行を表示
print(type(f[0].values))    # numpy.ndarray
print(f[0].values)    # DataFrameは属性valuesにNumPy配列のobject型として保存されている
f[0] = pandas.read_csv('data_2.tsv', sep = "\t", header = None, index_col = None)
    # headerやindexがないファイル
f[0] = pandas.read_csv('data_3.tsv', sep = "\t", index_col = 0, \
                               header = None, names = ('S1', 'S2', 'S3', 'S4'))
    # headerを付けて読み込む
f[0] = pandas.read_csv('data_4.csv', skiprows = 5, encoding = 'Shift_JIS')
    # 先頭5行を読み飛ばす, Shift_JISのファイル

読み込まれるデータは、適当に判断されてint, float, strといった型として格納される。慎重に処理したい場合は dtype = object で読み込み、後で astype('float') などと変換すればよい。

サイズを指定し値が初期化されていないデータフレームを作成する

import numpy
f[0] = pandas.DataFrame(numpy.empty((7, 5)))

7行5列のデータフレームを作成。

1つのリストからデータフレームを作成する

f[0] = pandas.DataFrame([3, 8, 5, 4])    # 1行4列ではなく、4行1列DataFrame
f[0] = pandas.DataFrame([3, 8, 5, 4], [5, 2, 1, 9])    # 2つめリストは4行のindexに
f[0] = pandas.DataFrame([[3, 8, 5, 4], [5, 2, 1, 9]])    # 2行4列DataFrame

新規にDataFrameを作成し、headerとindexを付ける

f[0] = pandas.DataFrame([[0.000, 0.000, 0.000, 0.000,  0.000],
                        [1.000, 1.000, 1.000, 1.000,  1.000],
                        [1.260, 1.414, 2.000, 4.000,  8.000],
                        [1.442, 1.732, 3.000, 9.000, 27.000]])
f[0].columns = ['A',  'B',  'C',  'D',  'E']    # headerを付ける、あるいは全体の変更
f[0].index   = ['I1', 'I2', 'I3', 'I4']    # indexをつける、あるいは全体の変更
    #         A      B    C    D     E
    # I1  0.000  0.000  0.0  0.0   0.0
    # I2  1.000  1.000  1.0  1.0   1.0
    # I3  1.260  1.414  2.0  4.0   8.0
    # I4  1.442  1.732  3.0  9.0  27.0
f[0].rename(columns = {'A': 'a', 'B': 'b'}, index = {'I1': 'i1'}, inplace = True)
    # headerおよびindexの一部を変更; 自身を変更する場合は inplace = True
f[0] = d0.rename(columns = {'a': 'aa', 'b': 'bb'}, \
             index = {'i1': 'ii1', 'I4': 'ii4'}, inplace = False)
    # inplace = False の場合は別なDataFrameに

Excelファイルを読み込みDataFrameにする

book = pandas.ExcelFile('data.xlsx')    # 既存ファイルを読み込む
print(type(book))    # pandas.io.excel._base.ExcelFile
print(type(book.sheet_names))    # シート名のlist
for ws in book.sheet_names:
  f[0] = book.parse(sheet_name = ws, header = None)    # f[0]に上書き
  print(ws, f[0], sep = '\n')    # シート名とDataFrameの内容を表示

OpenPyXlをインストールする必要がある (xlrd, xlwt, xlsxwriter等は不要)

DataFrameをExcelファイルに書き出す

with pandas.ExcelWriter('data.xlsx') as writer:
  data.to_excel(writer, sheet_name = 'data sheet 1')

いくつかのオプションを指定をしてExcelファイルを読み込む

foo = excel.parse(excel.sheet_names[0], skiprows = 10, header = 0,  parse_cols = 'C:G, J:K', index_col = 0)
# 最初の10行を読み飛ばし、次の行がheaderで、C列からG列とJ列とK列だけを読み込み、最初のC列をindex

DataFrameをpickleとして書き出し、読み込む

import pickle
with open('data.pickle', 'wb') as pickle_file:
  pickle.dump(d0, pickle_file)    # pickleファイルとして出力
with open('data.pickle', 'rb') as pickle_file:    # 既存pickleから読み込み
  d1 = pickle.load(pickle_file)

DataFrameをタブ区切りテキストファイルとして書き出す

f[0].to_csv('data.tsv', sep = '\t', index = True, header = True)    # 新規ファイルに出力

Excel等で出力されたShift_JISで書かれたカンマ区切りテキストを読み込む

import codecs    # UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte # こんなエラーが出た場合
with codecs.open('data.csv', 'r', 'Shift_JIS', 'ignore') as shift_jis_csv:
  f[0] = pandas.read_csv(shift_jis_csv, skiprows = 6)    # 先頭6行を無視
  print(f[0].iloc[0:8, 0:6])    # 8行6列までを確認

列数が一定でないテキストを読み込む

f[0] = pandas.read_csv('data.csv', names = range(8))    # namesでヘッダを付ける
# ParserError: Error tokenizing data. C error: Expected 1 fields in line 7, saw 10 # こんなエラーを回避

特定の列に列名でアクセスする

print(f[0]['Col3'])    # Series
print(f[0].Col3)    # Series
print(f[0][['Col5', 'Col3', 'Col1']])

特定の連続行にスライスでアクセスする

print(data[0:1])    # 0行目の1行だけのDataFrame
print(data[3:7])    # 3, 4, 5, 6行目のDataFrame

DataFrameの要素にアクセスする

(n_rows, n_columns) = data.shape	# 4096 (len(data) と同じ値), 4096 (len(data.columns) と同じ値)
print(data.iloc[13])    # 0から数えて13行目の1行全体にアクセス
type(data.iat[128, 256])    # numpy.float64; 0から数えて128行256列の要素にアクセス
print(sum(data.iloc[:, 256]))    # 256列目全体にアクセスし和を計算
import numpy
print(numpy.std(data.iloc[128, :]))    # 128行目全体にアクセスし標準偏差を計算
print(data.iloc[10:20, 40:60])    # 0から数えて、10から19行、40から59列までの部分を表示
print(data.iloc[[10, 20, 30, 40, 50], [150, 160, 170]])    # 指定した行や列のみを表示; headerやindexも表示される
print(data.loc[['foo', 'bar'], data.columns[8]])    # columnsを用いてラベルを取得しlocを利用
print(data.loc[data.index[16:32], 40:50])    # indexを用いてラベルを取得しlocを利用
要素の指定 単数要素(高速) 複数要素(高負荷)
ラベルで指定 at[ , ] loc[ , ]
番号で指定 iat[ , ] iloc[ , ]

行ラベルや列ラベルから行や列の番号を取得する

print(d.iat[d.index.get_loc('sample_23'), d.columns.get_loc('feature_19')])

列を追加および削除する

d0['feature13'] = None    # 列名を付けて1列追加
d0['feature14'] = [i for i in range(5)]    # リストを用意してもう1列追加
d1 =d0.drop(columns = ['feature13', 'feature14'])    # タプルではなくリストで, inplace = True でなければ非破壊
del(d0['feature13'], d0['feature14'])    # 先に追加した2列を削除

行を追加および削除する

d0.columns = ['ColumnA',  'ColumnB',  'ColumnC',  'ColumnD',  'ColumnE']
d0.index = ['Index01', 'Index02', 'Index03', 'Index04', 'Index05']
d1.columns = ['ColumnA',  'ColumnB',  'ColumnC',  'ColumnD',  'ColumnE']    # 列名を揃えてからappend()
d0 = d0.append(d1)
d0.drop(index = ['Index01', 'Index03', 'Index04', 0, 2])    # index名で指定; 非破壊なのでd0はの中身は変化なし
d1 = d0.drop(index = ['Index01', 'Index03', 'Index04', 0, 2])    # 5行削除されたデータフレームd1
d0.drop(d0.index[[0, 1, 3]], inplace = True)    # 行番号で削除したい場合はindex[[]]を利用

転置する

datat = data.T    # headerとindexは入れ代わる

pandas.concat()でDataFrameを連結する

print(f[0])
#     y2  y3  y4  y5
# x2   4   6   8  10
# x3   6   9  12  15
# x4   8  12  16  20
# x5  10  15  20  25
print(f[1])
#     y5  y6  y7  y8
# x4  20  24  28  32
# x5  25  30  35  40
# x6  30  36  42  48
# x7  35  42  49  56
print(pandas.concat(f[:2]), axis = 'index')    # headerに基づいて縦方向に連結 (indexの重複あり)
#       y2    y3    y4  y5    y6    y7    y8
# x2   4.0   6.0   8.0  10   NaN   NaN   NaN
# x3   6.0   9.0  12.0  15   NaN   NaN   NaN
# x4   8.0  12.0  16.0  20   NaN   NaN   NaN
# x5  10.0  15.0  20.0  25   NaN   NaN   NaN
# x4   NaN   NaN   NaN  20  24.0  28.0  32.0
# x5   NaN   NaN   NaN  25  30.0  35.0  40.0
# x6   NaN   NaN   NaN  30  36.0  42.0  48.0
# x7   NaN   NaN   NaN  35  42.0  49.0  56.0
print(pandas.concat(f[:2], axis = 'columns'))    # indexに基づいて横方向に連結 (headerの重複あり)
#       y2    y3    y4    y5    y5    y6    y7    y8
# x2   4.0   6.0   8.0  10.0   NaN   NaN   NaN   NaN
# x3   6.0   9.0  12.0  15.0   NaN   NaN   NaN   NaN
# x4   8.0  12.0  16.0  20.0  20.0  24.0  28.0  32.0
# x5  10.0  15.0  20.0  25.0  25.0  30.0  35.0  40.0
# x6   NaN   NaN   NaN   NaN  30.0  36.0  42.0  48.0
# x7   NaN   NaN   NaN   NaN  35.0  42.0  49.0  56.0
data = pandas.concat(f[2:5], keys = ('dataframe2', 'dataframe3', 'dataframe4'), axis = 'index')
data = pandas.concat(f[5:8], keys = ('dataframe5', 'dataframe6', 'dataframe7'), axis = 'columns')

keysを用いると、元のデータフレームを区別できます。

数値のみからなるDataFrameをNumPy配列に、またNumPy配列をDataFrameに変換する

data0 = pandas.read_csv('foo.tsv', sep = "\t", index_col = 0)    # headerとindex以外は浮動小数点数
import numpy
data = numpy.array(data0.iloc[0:32, 0:16])    # DataFrameの一部を取り出し、NumPy配列へ
numpy.set_printoptions(linewidth = 160, threshold = numpy.inf)    # 表示幅を160カラムに広げ、省略せずに全て表示
numpy.set_printoptions(precision = 4, suppress = True)    # 小数点以下4桁にまるめ、指数表示せずに
numpy.set_printoptions(formatter = {'float': '{: 0.4f}'.format})    # 小数点以下4桁まで表示
print(type(data))    # numpy.ndarray
print(data.shape)    # (32, 16)
print(data)
data1 = pandas.DataFrame(data)    # pandasのDataFrameに戻す
print(type(data1))    # pandas.core.frame.DataFrame

print()で表示する際に、折り返されないように、省略されないようにする

pandas.set_option('display.width', 512)    # 表示幅を広くする
pandas.set_option('display.max_columns', 8)    # 8カラムまで表示
pandas.set_option('display.max_rows', 256)    # 265行まで表示

重複する行を削除する

nonredundant = data_frame_1.drop_duplicates()    # uniqとは異なり離れている重複行も削除

欠損値か否かを判定する

print(f[0].isna())    # 欠損値は True となる
print(f[0].isnull())    # 同上
print(f[0].dropna()    # 欠損値のある行を削除

None あるいは numpy.nan などを代入することで欠損値にすることができる。

平均値など列ごとの統計データを取得する

print(d.count())    # Noneなどでない値の数
print(d.mean())    # 各列の平均 (列数に相当する数の平均値が出力される)
print(d.mean(axis = 1)    # 各行の平均 (行数に相当する数の平均値が出力される)
print(d.mean(axis = 'columns')    # 各行の平均 (行数に相当する数の平均値が出力される)
print(d.var())
print(d.std())
print(d.min())
print(d.max())
print(d.describe())    # 各種データを出力
print(d.corr())    # 相関係数
print(d['temperature'].mean())    # 特定の列の平均値

散布図行列を描く

pandas.plotting.scatter_matrix(data_frame.iloc[:, 1:5], figsize = (16, 16), c = list(data_frame.iloc[:, 0]), alpha = 1.0)
# 1列から4列目までのデータで散布図, figsizeは単なる図の大きさ, cで0列目のデータで色分けを指定, alphaは透明度で1から0まで小さくすると薄くなる

各列の要素に対して関数を適用する

normalized = data_frame.iloc[:, 1:].apply(lambda x: (x - x.mean()) / x.std(), axis = 0)
# 1列目以降の全ての列に対して、その列の平均で引いた後に標準偏差で割る

Seriesを作り複数のSeriesを列として結合する

s1 = pandas.Series(('foo', 'bar', 'baz'))    # リストをSeriesに
s1 = s1.append(pandas.Series(('qux',)))    # Seriesにして追加
s2 = pandas.Series((1792, 1804, 1806))
s2 = s2.append(pandas.Series((1811,)))
d = pandas.concat((s1, s2), axis = 1)    # 列として結合しデータフレームに
print(d)
#      0     1
# 0  foo  1792
# 1  bar  1804
# 2  baz  1806
# 0  qux  1811

列を指定してソートする

d = pandas.DataFrame(numpy.random.randint(20, 90, (8, 5), dtype = int))
d.index = ['r' + str(i) for i in range(8)]
d.columns = ['c' + str(i) for i in range(5)]
d.sort_values(by = 'c3', ascending = True, inplace = True)
print(d)
#     c0  c1  c2  c3  c4
# r2  46  29  62  20  70
# r1  70  65  24  24  38
# r0  33  60  55  42  79
# r5  68  71  73  67  86
# r3  41  68  83  68  49
# r6  37  52  30  73  82
# r4  61  75  36  82  54
# r7  28  55  27  85  61

列内の重複数を確認する

print(d['Name'].value_counts())    # Name列内の重複

ウェブサイトの表を取得する

tables = pandas.read_html(url)    # URLの文字列を引数で与えるとDataFrameのリストが得られる

グラフを描く

d.plot()    # DrataFrameあるいはSeriesのメソッドplot()で数値列のみの折れ線グラフ
d.plot.bar()    # 棒グラフ
d.plot.box()    # 箱髭図
d.plot.hist()    # ヒストグラム
d.iloc[:, 3].plot.pie()    # 円グラフ

条件を指定して各要素に値を代入する

f[0][((f[0].values % 3 == 1) & (f[0] > 50)) | (~ (f[0] > 10))] = numpy.nan

論理積、論理和、否定はそれぞれ &, |, ~ で表現する。
valuesは使わなくても動作する。
上の代入文は、データフレームの全ての値を調べて、3で割った余りが1で、かつ50よりも大きいか、あるいは10以下の要素に対して全て numpy.nan を代入して NaN にする。

全ての要素に対し関数を適用する apply()

def add(x: float, y: float) -> float:
  return x + y    # xに対しyを足してその結果を返す関数
r = pandas.DataFrame(numpy.empty((3, 5), dtype = float),
        index = tuple('ABC'), columns = tuple('abcde')))
print(r)
print(r.loc['B',].apply(add, args = (0.1,)))    # 特定の行に対して
print(r['d'].apply(add, args = (0.2,)))    # 特定の列に対して
print(r.apply(add, args = (0.7,)))    # 全ての要素に対して
print(r)    # r自体はapply()によって変化しない

シリアライズする

pickleにするメソッドがあり、ファイル拡張子で xz などと指定すると自動的に圧縮、解凍も行われる。

f[0].to_pickle('f0.xz')
f[1] = pandas.read_pickle('f0.xz')
9
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?