89
128

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 5 years have passed since last update.

すごいPandasさっくり学ぼう

Last updated at Posted at 2017-01-29

すごいPandasさっくり学ぼう

はじめに

Pandasとはプログラミング言語Pythonにおいて、データ解析を支援する機能を提供するライブラリです1PandasPythonのライブラリでも複雑だと思います2。 しかし、その分、自由度が非常に高く、データ分析やさんにとって、Pandasなしでのデータ分析は考えられません。そこで、「ここまで理解しとけば、あとは(他サイトとかみたら)どうにでもなるわ」ってところまで説明したいと思います3

攻略方法

\1. 準備

  • numpy(1次元)のインデックス参照、スライシング、ブールインデックス参照、ファンシーインデックス参照を使えるようにする

  • numpy(2次元)のインデックス参照、スライシング、ブールインデックス参照を使えるようにする。numpy.iloc_関数の挙動を理解する。(ファンシーインデックス参照は2次元でのndarrayでは使いづらい仕様になっているので、個人的にはほとんど使わない)

\2. Pandas入門

  • Series, DataFrameの作成、インデックス参照を使えるようにする(Seriesは基本的にnumpy(1次元)の拡張。DataFrameは基本的にdf.loc(ラベル名優先)またはdx.iloc(番号優先)を用いれば基本的にnumpy(2次元)の拡張。)

  • Series, DataFrameのデータ追加、抽出、削除、修正などをできるようにする

  • (Series, DataFrame内の要素やindex名が文字列なら、抽出や修正の一括操作が可能。便利なので、Pandasstrアクセサによる文字列処理を理解する)

ぐらいまでやっておくと、あとは軌道に乗って自分でいろいろ調べられるレベルに到達するはず(groupbyとかも[1]とかでスムーズに理解できるはず)。

  • 全体を通して言えるのが、特に演算後のdimension(次元)がいくつなの?ということをコードを書く際に常に意識することが大事だと思います。

例えば、Numpyなら、

arr = np.arange(12) # arrは1次元のndarray
arr = arr.reshape(3,4) # arrは2次元のndarrary
# arr[i,j]の第一要素は行、第2要素は列
arr[:2] # 2次元のndarray
arr[:2, 0] # 1次元のndarray
arr[:, arr[0] > 2] #2次元のndarray

Pandasなら、

pop = {'Nevada' : {2001 : 2.4, 2002 : 2.9},
       'Ohio' : {2000 : 1.5, 2001 : 1.7}}
df = DataFrame(pop) # DataFrame(2次元)
df[df['Nevada'] > 2] # DataFrame(2次元)
df.iloc[-1:]['Nevada'] # Series(1次元)

というような感じで、型は何なん?ってことを意識し理解すれば、半分は終わったようなもんです。


というわけで、ndarray(2次元)のインデックス参照の挙動をまとめてから、Pandasに進むことにしましょ〜

準備

import

import numpy as np # ndarray
# matplot をjupyterで表示するのに必要
%matplotlib inline
import matplotlib.pyplot as plt
from pandas import Series, DataFrame
import pandas as pd

Numpy

2次元のndarrayを取り上げます。Pandasを理解するためにここで理解することは、以下の二つです:

  • Numpyのインデックス参照、スライシング、ブールインデックス参照、ファンシーインデックス参照をきちんと理解している

  • 2次元のNumpyarr[<行指定>], arr[<行指定>, <列指定>]である(こんがらがらずに理解できている)。

arr = np.arange(12).reshape(3,4) # arrは2次元のndarrary(3行4列)
#array([[ 0,  1,  2,  3],
#       [ 4,  5,  6,  7],
#       [ 8,  9, 10, 11]])
  • indexerの引数が1つだけのときは以下のような感じになります:
# 1次元のndarrayを得る
arr[1] # スカラー値で要素参照
arr[0:2] # スライシング 0行目と1行目を抽出する(2行目は抽出されない)
## 一行目の各要素に対して、(>2)の真偽値を返す
arr[1] > 2 # array([ True,  True,  True,  True], dtype=bool) 

# 2次元のndarrayを得る
arr>2 # ブールインデックス参照
arr[np.array([True, False, True])] # ブールインデックス参照で0行目と2行目を抽出する
# arr[[True, False, True]] # Warning
arr[[0,2,1]] # ファンシーインデックス参照 : インデックス参照に(整数)配列を用いる 0行目と2行目と1行目を順序付きで抽出する
  • Numpyのindexer(2次元なら arr[・(第一引数), ・(第二引数)])とします。第一引数が行、第二引数が列にあたります。

基本的には1次元のndarrayと同じなのですが、陥りやすい落とし穴だけメモします:

# 第二引数のみを指定したい時。第一引数は省略できない。その時はスライシング`:`を第一引数としておく
arr[:, 1]

# 第一引数、第二引数にファンシーインデックスを指定すると、ちょっと直感的でない動作をする。
## (1次元のndarrayになってしまうことも注意すること!
## np.array([arr[i,j] for i,j in zip([1,2], [0,1])])と同等。 # array([4, 9])
arr[[1,2], [0,1]]
## 1,2行目かつ0,1列目の領域を抽出するような2次元のndarrayを取得するには、次のようにやる
arr[np.iloc_([1,2], [0,1])]
array([[4, 5],
       [8, 9]])
  • Numpy自体でこういう書き方をする機会は限りなく低いのですが、Pandasを使用する際に考え方が重要になってくるので、以下に記述しておきます(とりあえず飛ばしてOK):
# 行
arr[:,1] > 2 # array([False,  True,  True], dtype=bool)

# 1列目が(>2)であるような行を抽出する
arr[arr[:,1] > 2] # arr[np.array([False,  True,  True])]と同じ。(個人的にはあんまり使ったことない)
# arr[arr[:, 1] > 2, :]と同じ。


arr[1] > 5
arr[:, arr[1] > 5] # array([False, False,  True,  True], dtype=bool)
#arr[:, np.array([False, False, True, True])] # と同じ

まとめると、ndarray(2次元)のインデックス参照の型の挙動は以下のような感じです4

第一引数\第二引数|なし|スカラー|スライシング|ブールインデックス|ファンシーインデックス
---|---|---|---|---|---|---|---|---|---|---|---
なし|-|❌|❌|❌|❌|
スカラー|1d|0d|1d|1d|1d|
スライシング|2d|2d|2d|2d|2d|
ブールインデックス|2d|1d|2d|(2d)|(1d)|
ファンシーインデックス|2d|1d|2d|(1d)|(1d)|

  • 他には、普通のlistとの挙動の違いは押さえておきたい(微妙に違う)
# 以外と間違えてしまう罠。arrの要素を3倍にしたい
> arr = [0,1,2,3]
> arr*4
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]

> np.arange(4)*4
[0,4,8,12]
# numpyに変換せずに同様のことを行うならば、内包表記で。
> [i*4 for i in range(4)]
[0,4,8,12]

Pandas入門編

Numpyでは、1次元であろうが2次元であろうが、同じndarrayとして扱えばよかったんですが、Pandasでは、1次元 => Series, 2次元 => DataFrameとして分かれています。なので、名前は違えど、2次元 <=> 1次元の行き来をするため、DataFrameSeriesを切り離すことはできません。

例えば、DataFrameから単一行/列を指定すれば、1次元であるSeriesを抜き出すことができます。逆にSeries(1次元)のlistordictDataFrame(2次元)のコンストラクタの引数に指定することでDataFrameを作成することができます。

ということで、変数の次元が1次元なのか2次元なのかを理解することはSeries, DataFrameと名前が変わっても重要になるわけです。

Seriesについて

Seriesの作成

基本的に、コンストラクタにdict, listを突っ込むことが多いです。dictの場合は、index付きのSeriesになります。

# dictを突っ込む例
dic = {'word' : 470, 'camera' : 78}
Series(dic)
# zipとdictの合わせ技でSeriesを生成することもよくあります:
Series(dict(zip(words, frequency)))

インデックス参照

インデックス参照については、1次元のndarrayの拡張です。違いとしては、index名もインデックスの引数として入れることができる点です。

ser = Series(np.random.randn(5), index = list('ABCDE'))
#A    1.700973
#B    1.061330
#C    0.695804
#D   -0.435989
#E   -0.332942
#dtype: float64

# スライシング
ser[1] # 1行目、つまり'A'行を抽出 0次元(type = float64型) 
ser['A'] # 'A'行を抽出(type = float)
ser[1:3] #1,2行目を抽出 (Series(一次元)
ser[-1:] # 最後の行を抽出
ser[:-1] # 最後の行を除く全ての行を抽出
ser[[1,2]] # 1,2行目を抽出(ファンシーインデックス)
ser[['A', 'B']] # (ファンシー)インデックスを文字列で与えることもできる
ser > 0 # serの型はSeries(1次元)で各要素は真偽値 
ser[ser > 0] # ブールインデックス(ser > 0)で要素参照

# Read, Write両方できるので、以下のように、該当するもののみに右辺値を書き込むこともできる.
# 左辺値に条件を持っていくテクニックはDataFrameでもよく使う。
ser[ser > 0] = 0

DataFrameについて

DataFrameの作成

  • 2次元のものをコンストラクタの引数に突っ込むわけですけど、外側がlist or dictならば、内側はほとんど何でも構わない(listでもSeriesでもdictでもtupleでも可)
# 外側も内側も dictの場合
pop = {'Nevada' : {2001 : 2.4, 2002 : 2.9},
       'Ohio' : {2000 : 1.5, 2001 : 1.7}}
df2 = DataFrame(pop)
#      Nevada  Ohio
#2000     NaN   1.5
#2001     2.4   1.7
#2002     2.9   NaN

# 外側がdict, 内側がseriesの場合 
# df1, df2はDataFrame型 (なので、df1['name'], df2['address']はSeries型です)
## column名は['typeA', 'typeB'], index名は[0,1,2,3]
dfA = DataFrame({'typeA' : df1['name'], 'typeB' : df2['address']})
## index名は[0,1,2,3], column名は['name', 'address'] (attributeのTは転置)
dfB = DataFrame([df1['name'], df2['address']]).T
  • builtinのzip関数を使って、DataFrameを作ることもよくあります:
dict(zip([1,2,3], [4,5,6,7])) #{1: 4, 2: 5, 3: 6} => DataFrame化できない
list(zip([1,2,3], [4,5,6,7])) #[(1, 4), (2, 5), (3, 6)] => DataFrame化できる(外側:リスト、内側:タプルなので)
pd.DataFrame(list(zip([1,2,3], [4,5,6,7]))) # => OK!
  • 2次元ndarrayを突っ込んでもDataFrameの作成が可能です。
df = DataFrame(np.arange(12).reshape(3,4), columns = list('ABCD'))
print(df)
   A  B   C   D
0  0  1   2   3
1  4  5   6   7
2  8  9  10  11
  • Seriesとの合わせ技でDataFrameを作成することも。
DataFrame(Series({'word' : 470, 'camera' : 78}), columns = ['frequency'])

SeriesからのDataFrame作成は、初心者編のデータ追加の節でも詳しく見ていきます。

DataFrameのインデックス参照

Pandasではdf[・] ordf.loc[<行指定>]or,df.loc[<行指定>, <列指定>]or df.iloc[<行指定>] or df.iloc[<行指定>, <列指定>]ができます。df[・]は以下のように結構紛らわしい挙動をします。

# よく使う
#dfA[1] # runtime error!! 一列目を整数値で取り出せない
#dfA['typeA'] #'typeA'列をSeries(1次元)として抽出
dfA[['typeB', 'typeA']] # typeB, typeA列を順序込みでDataFrame(2次元)として抽出
dfA['typeA'] > 3 # 1次元のSeries (各要素は真偽値)


# ちょっとややこしい(が個人的にはよく使う)
dfA[dfA['typeA'] > 3] # dfAの'typeA'列が3以上である行を抽出。
# dfA.loc[dfA['typeA'] > 3] #不安なら こちらを使うべし


# 以下、かなりややこしいので、あまり使わない。
dfA[1:] # 1行目~をDataFrame(2次元)として抽出(行の抽出であることに注意)
#dfA[1:]よりも自分ならこう書く。
dfA.loc[1:] # 行指定であることを明示。もしくは、dfA.loc[1:, :]

df.locNumpyのラベル名指定もOKなバージョンです。ということで、基本的に、Numpyのインデックス参照と同じノリで書けばよろしい.

df.locの注意事項

ただし、df.locを扱う際の注意事項としては、2つあります(結構重要かつはまりやすい)。

一つは、df.locはラベル名優先なので、indexに整数値が指定されていた時もインデックスの番号が参照されるのではなく、ラベル名に対応する行が抽出される点です。例えばsortして1番目までの行を抽出したい時とかは、結構事故になりやすいです:

dic = list(zip([0,3,5,6], list('ADCB')))
dfA = DataFrame(dic, columns = ['typeA', 'typeB'])
#   typeA typeB
#0      0     A
#1      3     D
#2      5     C
#3      6     B
dfA = dfA.sort_values(by = 'typeB')
#   typeA typeB
#0      0     A
#3      6     B
#2      5     C
#1      3     D
dfA.loc[1] #1番目の(つまり2位の)行を抽出したいが、locを用いると、indexのラベル名1の行が抽出される:
#typeA    3
#typeB    D
#Name: 1, dtype: object


## こういう悲惨なことを防ぐには、df.ilocを用いる。行番号が優先される。
##(#3      6     B)が抜き出せる
dfA.iloc[1]

ilocは抽出後にもよく使います.(indexが番号順で無くなっている場合はloc[番号]で参照できない)

df = df[df['A'] == name]
df.iloc[0]['B'] # ちょっとすっきりしない感じはするが...

もう一つは、これも整数値インデックスを扱う場合に陥りやすい罠ですが、最終行を抜き出したいときは、df.locに負の値を要素参照すると失敗します。ラベル名優先なので、-1のラベルなんてないよ〜って言われるわけです。この場合もdf.ilocを用いて、行番号に関する抽出であることを強調することで解決します。

# dfA.loc[-1] : NG
dfA.iloc[-1] # OK(最終行がSeries(1次元)として抽出される)
dfA.iloc[-1:] # OK(最終行がDataFrame(2次元)として抽出される)

逆にdf.ilocは番号しか使えないので、行は行番号で、列はラベル名で指定したい時は、以下のように書くと良い。

df.iloc[i]['A'] # こう書くのが良い
# ilocは列指定は数字しかできない
# Location based indexing can only have
# [integer, integer slice (START point is INCLUDED, END point is EXCLUDED), listlike of integers, boolean array] types
# res *= df.iloc[i, 'A'] #error

DataFrameのインデックス参照についてまとめると、

  • 不安なら、df[・]よりもdf.loc[<行指定>]or,df.loc[<行指定>, <列指定>]を用いる。

  • ただし、行番号の抽出を強調したい場合は、df.iloc[<行指定>] or df.iloc[<行指定>, <列指定>]を用いる。

の2点だけ頭に入れとけば、Numpyのインデックス参照と同じように楽しいデータ抽出ができます。本当はdf.locの一種類のみ覚えれば良いなら気楽なんですが、整数値インデックスは実用上非常によく用いられるので、df.ilocの使用を避けるわけにはいかないのですよ :sweat:

補足

loc, ilocは以下のようにindexerを2重に使うとコピー <= 左辺値に置けない.(もとのDataFrameの修正したい値が修正されない)

#A value is trying to be set on a copy of a slice from a DataFrame
df.loc[5]['colA'] # 左辺値にはできません

# 問題なし! (参照なので)
df.loc[k, 'non_view_rate'] *= mult

Pandas初心者編

ここまではPandasのインデックス参照について見ていきました。たぶん山場は超えたのですが、DataFrameの追加とか修正とかそこらへんのややこしい部分が残っております。各関数の基本的な使い方については、 Pythonによるデータ分析入門-―NumPy、pandasを使ったデータ処理 にお任せして、ここでは、逆引き的な感じにまとめていきたい。

Pandasを用いたで〜たの整形方法

追加(連結)

ser = Series([1,2,3], index = list('ABC'))
#A    1
#B    2
#C    3
#dtype: int64

Series(3*1)と表現することにします。index名は全て同じとします。(['A', 'B', 'C']) いろいろなパターンのデータの連結方法を見ていきます。

(Series(3*1) <- Series(3*1)) -> DataFrame

  • DataFrame(2*3)にしたい
DataFrame([s1, s2]) #コンストラクタをもちいて
  • DataFrame(3*2)にしたい
df = DataFrame([s1, s2], index = list('AB')).T
pd.concat([s1, s2], axis = 1) # 下方向に積み上げたいときはconcat(.., axis = 1)を用いれば良い
  • DataFrame(6*1)にしたい
serA.append(serB)
# または、
pd.concat([serA, serB])
# インデックス名を0の連番にしたければ..
s1.append(s2).reset_index(drop = True) # インデックスを再振り分け
  • DataFrame(1*6)にしたい
df1 = DataFrame(serA)
df2 = DataFrame(serB)
ndf = df1.join(df2, how = 'outer', lsuffix = 'A', rsuffix = 'B') #かなぁ
# こっちは二つしか連結できないけれど。
ndf = pd.merge(df1, df2, left_index=True, right_index=True, how='outer') 
   0A  1A  2A  0B  1B  2B
0   1   2   3   4   5   6

(DataFrame(n*3) <- Series(3*1)) => DataFrame

  • DataFrame((n+1)*3)にしたい
# Can only append a Series if ignore_index=True or if the Series has a index name
df.append(serA, ignore_index = True)

cols = ['colA', 'colB', 'colC']
res_df = DataFrame(columns = cols)
res_df = res_df.append(Series([1,2,3], cols).T, ignore_index = True)
...

複数のSeriesを積み重ねたい

  • こんなかんじにしたい

(Series(3*1) + Series(3*1)) + Series(3*1) + Series(3*1)-> DataFrame(4*3)

df = DataFrame([serA, serB, serC, serD])
# DataFrame(3*4)にしたい場合は.Tをつければ良い
df = DataFrame([serA, serB, serC, serD]).T

既存のDataFrameに最終行(Series)を下方向に追加したい(または下方向にDataFrameを追加する)

# 1行追加
df.loc['newrow'] = 0
df.append(serA, ignore_index = True)
# 複数行を追加
df1.append(df2)
# 複数のDataFrameを追加(リストを突っ込める)
df1.append([df2, df3, df4])
# または、
pd.concat([df1, df2, df3, df4])

# 1列追加
df['newcol'] = 0

indexがほぼ共通していて,dfを右方向につなげたい

# 該当しないindexは外部結合(outer)にする。(NAN値にする。)
df1.join(df2, how = 'outer')
df1.join([df2, df3], how = 'outer')
# mergeはもっと細やかなことができるが、2つのDataFrameの結合に限定される:
df1.merge(df1, how = 'outer')

その他の追加

  • データベース風のマージdf1.merge(df2)とかについては、[1]とかを参考にしてください。

その他くわしきことは、公式ページ http://pandas.pydata.org/pandas-docs/version/0.19.1/generated/pandas.DataFrame.merge.html とか、 http://sinhrks.hatenablog.com/entry/2015/01/28/073327 がいいかな、と思います。

後者については、

+ 縦方向のシンプルな連結 DataFrame.append
+ 柔軟な連結 pd.concat
+ 列の値による結合 pd.merge
+ index による結合 DataFrame.join (mergeのmake easy版)

のようなことが図、例とともに書かれているので、わかりやすいです。


DataFrameの内容を修正する

index, columnsの名前を全部変更したい

# indexの名前変更
df.index = ['one', 'two', 'three']
# indexの番号再振り分け
df.reset_index(drop = True) # インデックスを再振り分け(0番から~)

# columnsの名前変更
## table作成=>編集後はcolumnが想定する並びになっていない可能性があるので、
## 明示的にcolumnの並びを指定した方が無難。
df = df[['old_a', 'old_b', 'old_c']] 
df.columns = ['new_a', 'new_b', 'new_c']

# もしくは、df.renameを使う
df = df[['old_a', 'old_b', 'old_c']] #columnの並び順を気にしなければどっちでも。
# renameは破壊的メソッドではないので、左辺値に代入する必要がある。parameterはcolumnsを指定。(axisパラメータではないことに注意)
df = df.rename(columns = {'old_a' : 'new_a', 'old_b' : 'new_b', 'old_c' : 'new_c'})

Note1) 一部のindex, column名を変更したいときにもdf.renameが使える。(indexcolumnsパラメータにdict型(変更前-変更後の対応表として)を指定する。axisパラメータはないので、注意すること。あとは、columnでなくcolumns(sをつける))

Note2) reindexは既存のindexの位置の入れ替えであって、index名の変更ではない。
set_indexはdf.set_index(['c1','c0'])というように、特定の1つ以上の列をインデックスとして使用した新しいオブジェクトを作成する。indexの名前の変更するメソッドではないことに注意。reset_indexは階層型インデックスが列に変換される。ちょうどset_index <=> reset_indexの関係。

代入

  • ある列内で所要の条件に当てはまった行の別の列を変更する
# 'A'列に着目して、'wrong'である行を選択し、それらの行の'B'列を'sth'に変更する
df.loc[df['A'] == 'wrong', 'B'] = 'sth'
  • sort_index(indexを軸にしたソートの場合), sort_values(特定の列(byで指定)で昇順,降順にsortできる(降順のばあいは, ascending = Falseを指定)

抽出

  • df[・]に複数のブールインデックスを入れたいばあい。

# それぞれのブールインデックスはカッコで囲むこと
df = df[(df['A'] > 0) | (df['B'] > 0)]
  • df[・]の要素それぞれについて複数の候補内にあるかを調べたい場合
# applyはSeriesを引数にとる関数(ラムダ式)を第一引数に突っ込む
# mapは要素を引数にとる関数(ラムダ式)を第一引数に突っ込む
df = df[df['A'].map(lambda d : d in listA)]

削除

行、列の削除はdf.dropで(non-destractive)。axisを指定すれば、行でも列でも削除可能

df = df.drop("A", axis=1)
# columnが'A', 'B', .. 'F'で'C'列から'F'列まで削除したいときとかは、以下のようにする方が多い
df = df[['A', 'B']]

naを取り除く

http://nekoyukimmm.hatenablog.com/entry/2015/02/25/222414 を参照。

  • NANの含まれている部分の行や列を丸ごと削除したい時はhow = 'all'を指定すればOKです。

ブールインデックス参照

  • ブール型の取得方法
# DataFrame型を返す
df.apply(lambda ser: ser % 2 == 0)
df.applymap(lambda x: x % 2 == 0)
df['goal'] == 0
df.isin([1,2])
df = df[~df.index.duplicated()] # indexの重複の削除(2回目以降に出てくるデータを削除)
# Series型を返す
df.apply(lambda ser : (ser > 0).any())
df['A'].map(lambda x : x > -1)
serA > serB # series型
-bool_ser # boolインデックスの要素のインデックスをひっくり返す
# 第二引数は第一引数でFalseになる要素のみ
df['A'].where(df['A'] > 0, -df['A']) # absのSeries版(第一引数に当てはまらなければ、負の符号をつける(つまり、負に負をかけるので、正になる)
(df['goal'] == 0).all() # 条件に全てあてハマっていれば、True
df.apply(lambda ser: ser % 2 == 0)
(df['cdf(%)'] < 90).sum() # 条件に当てはまる個数をカウント
df.where(df % 3 == 0, -df)

NA値が割り当てられる可能性のある書き方

結構、NA周りではまることも多いので、どこで NA値を発生させる可能性があるのかをメモ。

  • コンストラクタのindex, columns
dic = dict(zip(list('ABCD'), [3,4,6,2])) # dictを生成
ser = Series(dic, index = list('ABCDE'))
# dicにないE列がNANになっている
#A    3.0
#B    4.0
#C    6.0
#D    2.0
#E    NaN
#dtype: float64
  • DataFrameコンストラクタのdataパラメタに辞書に乗っていない

(例)

pop = {'Nevada' : {2001 : 2.4, 2002 : 2.9},
       'Ohio' : {2000 : 1.5, 2001 : 1.7}}
df = DataFrame(pop)

      Nevada  Ohio
2000     NaN   1.5
2001     2.4   1.7
2002     2.9   NaN
  • df.reindexでindexパラメータにdfのindexに含まれないものが入っている場合。

例は省略

  • locフィールドを用いたインデックス参照
df.loc[[2002, 2001, 1999], ['Alaska', 'Nevada']]

      Alaska  Nevada
2002     NaN     2.9
2001     NaN     2.4
1999     NaN     NaN

Note) df['non_exists'], df.loc[:, 'non_exists'] (columnに無い名前を指定してしまう)とエラー。

  • データフレーム同士の加算(index or columnの対応しない要素がNANになる)

  • merge, joinhow='outer'とかを指定した場合

  • append, concat(indexが対応していない場合)

NA値を取り除く方法

  • df.dropna(parameterはhowとかaxisとか), df.fillna(0)(NA値を一律0にする

  • df.reindexfill_valueパラメータまたは methodパラメータを指定

  • combine_first : old_df のNA値のみが第一引数によって補完される。(old_dfで要素が0になっている箇所はパッチあての対象とならないので、注意!)

# df .. indexが飛び飛び(index.name : B_idx, columns = ['A'] => indexを連番(0~89)として、補間値を0としたい
old_df = DataFrame(index = range(90), columns = 'A')
new_df = old_df.combine_first(df).fillna(0) # index.nameは消える

文字列の操作

特にSeriesの文字列操作は地味によく使うので。要素だけでなく、index名、column名に対しても、使えます!

詳しくは、 http://pandas.pydata.org/pandas-docs/stable/text.html (特に最下部)をみてください。DataFrame内で文字列操作をしたい時は、だいたいここみれば解決します。

使い所としては、例えば、ある正規表現にマッチする行だけを抜き出したい場合とか。

# dfの'A'列の中で先頭が英小文字に当たる行のみを抽出して、dfを更新する
r = '^[a-z]'
df = df[df['A'].str.match(r)] # df['A'].str.match(r)はブールインデックス

参考文献

[1] Pythonによるデータ分析入門-―NumPy、pandasを使ったデータ処理

[2] http://sinhrks.hatenablog.com/entry/2015/01/28/073327

[3] Documentation http://pandas.pydata.org/pandas-docs/stable/api.html

  1. https://ja.wikipedia.org/wiki/Pandas 参照

  2. でも難しいって言えない雰囲気がある。

  3. Pandasは言語ではないんだけど、題名がしっくりきたので。

  4. やや強引ですけど。第二引数の「なし」の列はarr[・]をさしてます。(1d)の丸括弧とかは、あんまり使わないことを意味します。1dは1次元のndarray、2dは2次元のndarrayを表します。

89
128
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
89
128

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?