Python tips (随時更新)
いずれしらべる
- タイムスタンプから月だけ取り出す
- データフレームをスライシングし処理していくループのpythonicな書き方
- .ixがなくなり.iloc, .locだになるので違いをまとめておく
- リストに要素を追加
- 論理ベクトル同士をクロス集計
- Seriesを結合してデータフレームをつくる
- _の意味 initや for _
- pythonicとは: effective python
システム
“init"とself
- “init”: クラスのインスタンスを作成したときに初期化処理を行うメソッド
- self: オブジェクトを参照する
- “str”:
アンダースコア(_) の意味: ユーザに見せない処理をする変数を表す。
- アンダースコア二つで定義される関数は外部の参照を受けないもの。この場合、アンダースコアで囲う。
- アンダースコア一つで定義される関数は参照はできるが、基本的に外部から参照しない ということを慣習化させたものらしい。
class person(): def __init__(self, name): self.name = name hunter = person('Elmer Fudd') print(hunter.name)
import os
os.chdir(path)
- StringIO
pandas
日付・時刻
- 処理時間の計測
import time start = time.time() # 処理 duration = time.time() - start print(duration)
- .dt.days: pandas.timedeltaをintにする
- Seriesのメソッドなのでリストでは使えない。
import pandas as pd import datetime as dt x = pd.to_datetime(pd.Series(['20170701', '20170702'])) y = pd.to_datetime(pd.Series(['20170710', '20170730'])) d = y - x print(d.dt.days)
merge
# サンプルのデータフレーム生成 (<http://sinhrks.hatenablog.com/entry/2015/01/28/073327> より。感謝) import pandas as pd df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=[0, 1, 2, 3]) df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7'], 'C': ['C4', 'C5', 'C6', 'C7'], 'D': ['D4', 'D5', 'D6', 'D7']}, index=[0, 1, 2, 5])
- indexでマージする
- right_index=True, left_index=True とする
pd.merge(d1, d2, , right_index=True, left_index=True, how='left') A_x B_x C_x D_x A_y B_y C_y D_y 0 A0 B0 C0 D0 A4 B4 C4 D4 1 A1 B1 C1 D1 A5 B5 C5 D5 2 A2 B2 C2 D2 A6 B6 C6 D6 3 A3 B3 C3 D3 NaN NaN NaN NaN
データフレーム
データフレームの複数の列を基準として、外れ値を除外する
import pandas as pd import numpy as np from scipy import stats df = pd.DataFrame(np.random.randn(100, 3)) # 外れ値として100を挿入 df.loc[0, 0] = 100 print(df.head()) # 100以上の値がある業を全て除く df[(df < 100).all(axis=1)] # 全体を標準化して3SD以上を除く df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]
- 各変数ごとに外れ値基準を計算して除外
import pandas as pd df = pd.DataFrame(np.random.randn(10, 3)) df.head() def elout(df, fv= 0.05): print(df.shape) r = pd.DataFrame() for c in df: v = df[[c]] is_in = ((v >= v.quantile(fv)) & (v < v.quantile(1-fv))) r = pd.concat([r, is_in], axis=1) df2 = df[np.array(r).all(axis=1)] print(df2.shape) return(df2) elout(df)
forループでデータフレームを足していく
import pandas as pd df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}, index=[0, 1, 2, 3]) x = pd.DataFrame() for i in range(4): t = df1.loc[i, :] x = pd.concat([x, t], axis=1) print(x) ... A B C D 0 A0 B0 C0 D0 1 A1 B1 C1 D1 2 A2 B2 C2 D2 3 A3 B3 C3 D3
重複
- 重複行削除
d = pd.DataFrame({'a': [1, 2, 3, 1], 'b': [1, 3, 3, 1]}) d.drop_duplicates() a b 0 1 1 1 2 3 2 3 3 3 1 1 a b 0 1 1 1 2 3 2 3 3
- 一部の列名を変える: .renameでディクショナリを使う。 元データ変更の場合はinplace=True
- 行名を変えるときはindex={}
d = pd.DataFrame({'a': [1, 2, 3, 1], 'b': [1, 3, 3, 1]}) d.rename(columns={'a': 'xx'}) xx b 0 1 1 1 2 3 2 3 3 3 1 1
- 行合計や列合計で割る
import numpy as np import pandas as pd dat = pd.DataFrame({'a': np.random.randn(5), 'b': np.random.randn(5), 'c': np.random.randn(5), }) rsum = dat.sum(axis=1) >>> dat.div(rsum, axis=0) a b c 0 1.109889 -1.521357 1.411468 1 -0.221592 0.231812 0.989781 2 -0.045156 0.534391 0.510766 3 -0.127811 0.783268 0.344543 4 4.216794 27.485861 -30.702655
欠損値の扱い
- .isnan(): 要素ごとにNaN (Not a Number) かどうかを返す。
import numpy as np v = [1, 2, np.nan] [np.isnan(x) for x in v] ... [False, False, True]
- Series.isnull(): Series全体で調べる
import numpy as np import pandas as pd s = pd.Series([1, 2, np.nan]) s.isnull() ... 0 False 1 False 2 True dtype: bool
- .values.any(): どこかに欠損値があるか
s.isnull().values.any() ... True
- 欠損値ならTrue、そうでないならFalseをかえす
スライシング
- 一部の行や列だけ除く: .drop
d = pd.DataFrame({'a': [1, 2, 3, 1], 'b': [1, 3, 3, 1]}) # 行を除く d.drop(0) a b 1 2 3 2 3 3 3 1 1 # 列を除く d.drop('a', axis=1) b 0 1 1 3 2 3 3 1
ピボットテーブル
- 縦横で分けて集計
import pandas as pd import numpy as np df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 6, 'B' : ['A', 'B', 'C'] * 8, 'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 4, 'D' : np.random.randn(24), 'E' : np.random.randn(24)}) >>> pd.pivot_table(df, values='D', index=['B'], columns=['A', 'C'], aggfunc=np.sum) ... ... A one three two C bar foo bar foo bar foo B A 1.989904 -0.544853 -1.382726 NaN NaN 0.929173 B 0.370564 -1.321093 NaN -0.116037 0.125153 NaN C -0.975050 -3.429380 -2.340092 NaN NaN -0.735084
- groupbyで集計したものをpivotで整形する
- 集計したものはキー変数がインデックスになるが、インデックスを指定してはピボットできない。
- reset_indexで変数にしてからピボットする。
df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'], 'key2' : ['one', 'two', 'one', 'two', 'one'], 'data1' : np.random.randn(5), 'data2' : np.random.randn(5)}) gr = df.groupby([df['key1'], df['key2']]) grs = gr.sum() x = grs.reset_index() >>> x.pivot(index='key2', columns ='key1') ... ... data1 data2 key1 a b a b key2 one -2.106043 0.190401 0.232389 -1.706491 two 0.470106 1.871696 -1.518614 -0.059299
統計
散布図と相関係数
- 散布図
import numpy as np import matplotlib.pyplot as plt x = np.random.randn(1000) y = np.random.randn(1000) fig = plt.figure ax = fig.add_subplot(1,1,1) ax.scatter(x,y) ax.set_title('first scatter plot') ax.set_xlabel('x') ax.set_ylabel('y') fig.show()
- 散布図と回帰直線
from scipy import stats import numpy as np import matplotlib.pyplot as plt x = np.random.randn(1000) y = np.random.randn(1000) r = stats.linregress(x, y) x_line = [x.min(), x.max()] y_line = [r.slope * i + r.intercept for i in x_line] plt.scatter(x, y, color='blue', label=x, s=50) plt.plot(x_line, y_line, color='green', linestyle='-', lw=5)
- 散布図行列
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns dat = pd.DataFrame({'a': np.random.randn(10), 'b': np.random.randn(10), 'c': np.random.randn(10), 'd': np.random.randn(10), 'e': np.random.randn(10)}) # 単純な相関行列 dat.corr() # pandas pd.scatter_matrix(dat) # seaborn sns.pairplot(dat)
- 色を変えて複数の回帰直線を描く
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn from matplotlib import cm from scipy import stats dat = pd.DataFrame({'y': np.random.randn(1000), 'x1': np.random.randn(1000), 'x2': np.random.randn(1000), 'x3': np.random.randn(1000)}) # xの列名 xlabels = ['x1', 'x2', 'x3'] colors = cm.rainbow(np.linspace(0, 1, len(xlabels))) for x, c in zip(xlabels, colors): xv = dat[x] slope, intercept, r_value, _, _ = stats.linregress(xv, dat.y) x_line = [xv.min(), xv.max()] y_line = [slope * i + intercept for i in x_line] plt.scatter(xv, dat.y, color=c, label=x, s=50) plt.plot(x_line, y_line, color=c, linestyle='-', lw=5) plt.legend(prop={'size':14}) plt.xlim(-4, 3) plt.ylim(-4, 3)
重回帰分析
- statsmodelsを使って
- Rの結果と一致
import pandas as pd from statsmodels.formula.api import ols x1 = pd.Series([12, 12, 7, 17, 14, 9, 10, 13, 15, 12, 12, 15, 11, 14, 17, 17, 16, 15, 15, 10, 12, 9, 12, 12, 19, 11, 14, 15, 15, 15, 16, 15, 12, 10, 11, 12, 15, 13, 15, 12, 12, 12, 13, 17, 13, 11, 14, 16, 12, 12]) # 母親価値 x2 = pd.Series([2, 2, 2, 3, 2, 2, 3, 3, 3, 1, 3, 3, 2, 2, 4, 2, 4, 3, 4, 2, 2, 1, 2, 2, 4, 2, 3, 2, 3, 3, 2, 3, 2, 2, 3, 1, 2, 3, 2, 2, 2, 3 , 3, 3, 2, 3, 2, 4, 2, 2]) # 通園年数 y = pd.Series([6, 11, 11, 13, 13, 10, 10, 15, 11, 11, 16, 14, 10, 13, 12, 15, 16, 14, 14, 8, 13, 12, 12, 11, 16, 9, 12, 13, 13, 14, 12, 15, 8, 12, 11, 6, 12, 15, 9, 13, 9, 11, 14, 12, 13, 9, 11, 14, 16, 8]) # 協調性 dat = pd.concat([x1, x2, y], axis=1) model = ols("y ~ x1 + x2", data=dat).fit() print(model.summary()) OLS Regression Results ============================================================================== Dep. Variable: y R-squared: 0.314 Model: OLS Adj. R-squared: 0.284 Method: Least Squares F-statistic: 10.74 Date: Thu, 20 Jul 2017 Prob (F-statistic): 0.000144 Time: 11:36:54 Log-Likelihood: -106.98 No. Observations: 50 AIC: 220.0 Df Residuals: 47 BIC: 225.7 Df Model: 2 Covariance Type: nonrobust ============================================================================== coef std err t P>|t| [0.025 0.975] ------------------------------------------------------------------------------ Intercept 5.1716 1.665 3.107 0.003 1.823 8.520 x1 0.3027 0.147 2.064 0.045 0.008 0.598 x2 1.1259 0.471 2.389 0.021 0.178 2.074 ============================================================================== Omnibus: 0.276 Durbin-Watson: 2.411 Prob(Omnibus): 0.871 Jarque-Bera (JB): 0.348 Skew: -0.164 Prob(JB): 0.840 Kurtosis: 2.756 Cond. No. 76.2 ============================================================================== Warnings: [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
- scikit-learnを使って
from sklearn import linear_model clf = linear_model.LinearRegression() # 説明変数に "quality (品質スコア以外すべて)" を利用 X = pd.concat([x1, x2], axis=1).as_matrix() # 目的変数に "quality (品質スコア)" を利用 Y = y.as_matrix() # 予測モデルを作成 clf.fit(X, Y) # 偏回帰係数 print(pd.DataFrame({"Name":['x1', 'x2'], "Coefficients":clf.coef_}).sort_values(by='Coefficients') ) # 切片 (誤差) print(clf.intercept_)
#
## 参考 http://pythondatascience.plavox.info/scikit-learn/%E7%B7%9A%E5%BD%A2%E5%9B%9E%E5%B8%B0 http://pythondatascience.plavox.info/pandas/%E8%A1%8C%E3%83%BB%E5%88%97%E3%82%92%E5%89%8A%E9%99%A4 https://nkmk.github.io/blog/python-pandas-dataframe-rename/ http://nekoyukimmm.hatenablog.com/entry/2015/04/10/094432 http://sinhrks.hatenablog.com/entry/2014/10/13/005327 https://chartio.com/resources/tutorials/how-to-check-if-any-value-is-nan-in-a-pandas-dataframe/