Open11

pandasでよく使う操作

nabetsunabetsu

1. データフレームの作成

1-1. DataFrameの作成

Dictionaryを渡すことでDataFrameが自分で作成できる

# Pre-defined lists
names = ['United States', 'Australia', 'Japan', 'India', 'Russia', 'Morocco', 'Egypt']
dr =  [True, False, False, False, True, True, True]
cpc = [809, 731, 588, 18, 200, 70, 45]

# Import pandas as pd
import pandas as pd

# Create dictionary my_dict with three key:value pairs: my_dict
my_dict = {
    'country': names,
    'drive_right': dr,
    'car_per_cap': cpc
}

# Build a DataFrame cars from my_dict: cars
cars = pd.DataFrame(my_dict)

インデックスの設定

インデックスを指定しなければ0からの番号が自動で設定される。

後からインデックスを設定するには.indexに対応するlabelを代入すればOK

# Definition of row_labels
row_labels = ['US', 'AUS', 'JPN', 'IN', 'RU', 'MOR', 'EG']
# Specify row labels of cars
cars.index = row_labels

以下のように作成時にインデックスを指定することも可能。

scores_df = pd.DataFrame({'点数': scores},
                        index=pd.Index(['A', 'B', 'C', 'D', 'E',
                                        'F', 'G', 'H', 'I', 'J'],
                                        name='生徒'))

列と行に名前の設定

indexとcolumnsそれぞれにnameを設定することができる。
(groupbyやpivot_tableのときに設定されているやつ?)

frame3.index.name = 'year'; frame3.columns.name = 'state'
frame3
>>>
state	Nevada	Ohio
year		
2000	NaN	1.5
2001	2.4	1.7
2002	2.9	3.6

1-2. ファイルからの読み込み

ユースケース

同じレイアウトのファイルを複数読み込む場合

主にDB等外部のソースからデータ量が多すぎて複数のファイルに分割した場合を想定

df_list = []
for filename in tqdm(["[JST_OrderManagement_His1].rpt.pkl.gz",
                      "[JST_OrderManagement_His2].rpt.pkl.gz",
                      "[JST_OrderManagement_His3].rpt.pkl.gz"]):
    df = pd.read_pickle("../data/raw/pkl/" + filename)
    df_list.append(df[:-1])

JST_OrderManagement_His_df = pd.concat(df_list,
                                       axis=0,
                                       ignore_index=True)

CSV

pd.read_csvで読み込める

# Fix import by including index_col
cars = pd.read_csv('cars.csv')



  • インデックスの指定
    上記のようにインデックスがずれてしまう時はファイルのどの項目をインデックスにするかindex_colで指定ができる。指定には数字だけでなく項目名(ヘッダー名)で指定することもできる。
    特に日付(DatetimeIndex)を指定したい時に便利?
# Fix import by including index_col
cars = pd.read_csv('cars.csv', index_col=0)

# index_colを指定
medal_df = pd.read_csv(file_name, header=0, index_col='Country', names=columns)
  • 項目名の指定
    names=('A', 'B', 'C', 'D')のように任意の値を列名として設定することもできる。リストやタプルで指定する。

Pickleの読み込み

  • pickleはread_pickleで読み込みができる(.gzでも可)
df_list = []
for filename in tqdm(["[JST_OrderManagement_His1].rpt.pkl.gz",
                      "[JST_OrderManagement_His2].rpt.pkl.gz",
                      "[JST_OrderManagement_His3].rpt.pkl.gz"]):
    df = pd.read_pickle("../data/raw/pkl/" + filename)
    df_list.append(df[:-1])

JST_OrderManagement_His_df = pd.concat(df_list,
                                       axis=0,
                                       ignore_index=True)

Excelの読み込み

エクセルを読み込む(DataFrameに変換する)には以下2つの方法がある

  • ExcelFile.parse
  • read_excel

ExcelFile.parseだとエクセルのシートそのものが初回時にのみ読み込まれるが、read_excelを使うと引数に指定するのは対象ファイルのパスであるが、read_excelを使う都度にファイルの読み込みが発生するため、対象ファイルにシートがたくさんあったり、行数が多かったりするとパフォーマンスが低下する

stackoverflow - ExcelFile Vs. read_excel in pandas

ExcelFile

xlrdが必要なので、事前にインストールする。ないと以下のエラーが出る

ImportError: Missing optional dependency 'xlrd'. Install xlrd >= 1.0.0 for Excel support Use pip or conda to install xlrd.

# Excelファイルを読み込む
xls = pd.ExcelFile('data/' + FILE_NAME)

# 取り込み対象から除外できるデータがないかデータを見て確認する
# skiprows:先頭の何行を読み込まないかを指定する引数
# skip_footer:最後の何行を読み込まないか指定する引数
# usecols:読み込む列を指定
df = xls.parse('二人',
                skiprows = 10,
                skip_footer = 2,
                usecols = "H:CG")
nabetsunabetsu

2. Pandasの基本(Essential Functionality)

2-1. インデックス、項目名の操作

reindex

  • reindexで指定したインデックスを元に新しいobjectを作成できる。
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
obj2
>>>
a   -5.3
b    7.2
c    3.6
d    4.5
e    NaN
dtype: float64

rename

renameでインデックスを新しく振り直せる

order.rename(index=order['TARGET_DATE'])

以下のように列名を変更するのにも使える

df.rename(columns={ 0: 'monthly'})

pandas.DataFrameの行名・列名の変更

PandasのIndexの理解と使い方まとめ

  • reset_index
    • インデックスの値を解除して、0からの通番をインデックスにする
  • set_index
    • 指定した項目をインデックスにする

pandas.DataFrame, Seriesのインデックスを振り直すreset_index

reset_index

f

dropオプションを設定しないと元々あったインデックスが項目として設定される。dropにTrueを設定するとインデックスがそのままになる。

> print(cars.reset_index())
   index        country  drive_right  car_per_cap
0      0  United States         True          809
1      1      Australia        False          731
2      2          Japan        False          588
3      3          India        False           18
4      4         Russia         True          200
5      5        Morocco         True           70
6      6          Egypt         True           45

> print(cars.reset_index(drop=True))
         country  drive_right  car_per_cap
0  United States         True          809
1      Australia        False          731
2          Japan        False          588
3          India        False           18
4         Russia         True          200
5        Morocco         True           70
6          Egypt         True           45

以下のようにソートしたときにはインデックスをリセットするとソート後の結果でインデックスの数字をふる事ができる。

cars.sort_values(['car_per_cap']).reset_index(drop=True)
         country  drive_right  car_per_cap
0          India        False           18
1          Egypt         True           45
2        Morocco         True           70
3         Russia         True          200
4          Japan        False          588
5      Australia        False          731
6  United States         True          809

ソート

sort_valuesで項目を指定してソートができる。
複数の項目を指定することもできる

# 項目を指定してソート
df.sort_values(by=["項目1"], ascending=True)
# 項目1を昇順、項目2を降順
df.sort_values(by=["項目1", "項目2"], ascending=[True,False])

以下のようにlocで要素を指定するとキーを指定して並べ替えることもできる。

result.loc[ ['[18, 31)', '[31, 42)', '[42, 53)', '[53, 64)', '[64, 75)', '75+']]

daily	weekly	monthly
age_group			
[18, 31)	2.59	2.89	3.21
[31, 42)	12.11	12.92	13.72
[42, 53)	24.42	24.38	24.81
[53, 64)	25.29	25.01	24.84
[64, 75)	27.48	26.94	26.05
75+	8.11	7.86	7.37

また、項目で並び替えを行うときには以下のようにcolumnsで指定すればOK

pd.DataFrame(data, columns=['year', 'state', 'pop'])

pandas でソート

結合、連結

  • merge
    • 項目での結合もできる
    • joinより細かな指定ができる
    • 一度に結合できるのは2つまで
  • join
    • デフォルトでインデックス同士の連結
    • 複数のDataFrameを連結できる
# left_on, right_onでそれぞれのデータフレームの列名を指定する
pd.merge(df_ab, df_ac_, left_on='a', right_on='a_')

Pandasで複数のデータを横方向に結合するjoin関数の使い方

nabetsunabetsu

3. データフレームからのデータ抽出

アクセス方法は大きく分けて以下の3種類

  1. Slicing
  2. An individual index (through the functions iloc or loc)
  3. Boolean indexing

Slicing

一番シンプルな方法。

# 項目名を指定して対象項目のみを抽出(以下2つは同じ結果になる)
 >>>df['name']
 >>>df.name
 # 複数の列にアクセスするには列の名前のリストを渡す
 >>>df[['name', 'age']]
 # locを使っても大丈夫
 >>>df.loc[:, ['name', 'age']]
 # 条件を複数指定したいときはisinを使う
 df[df['city'].isin(['Tokyo', 'Osaka']]
 # 表全体ではなく、特定の列からサブセットを取り出すこともできる(生存者のうち年齢が30以上)
 df['survived'][df['age'] >= 30]

また、指定にあたっては[]を重ねるとDataFrameの形式で抽出できる。

# Print out country column as Pandas Series
print(type(cars['country']))

# Print out country column as Pandas DataFrame
print(type(cars[['country']]))

[]でインデックスの開始と終了を指定することで行を指定してセレクトもできる。

# Print out first 3 observations
print(cars[0:3])

# Print out fourth, fifth and sixth observation
print(cars[3:6])

An individual index(loc, ilic)

Slicingだけだと機能には限りがあり、numpyの2d-arrayのようにarray[rows, columns]の形でデータを抽出するにはlocやilocを使う必要がある

  • loc(label-based)
  • iloc(integer position-based)

locとilocは指定方法がラベル名かインデックスかの違いで実現できる結果は同じ。
以下の例ではlocとilocで返される結果は同じになる。

# Seriesを抽出
cars.loc['RU']
cars.iloc[4]

# DataFrameを抽出
cars.loc[['RU']]
cars.iloc[[4]]

# DataFrameで複数の項目を抽出
cars.loc[['RU', 'AUS']]
cars.iloc[[4, 1]]

また、以下のようにインデックスと項目の両方を指定することもできる。

# rowとcolumnの両方を指定して1つの項目を抽出
cars.loc['IN', 'cars_per_cap']
cars.iloc[3, 0]

# 複数のrowと一つのcolumnを指定
cars.loc[['IN', 'RU'], 'cars_per_cap']
cars.iloc[[3, 4], 0]

# 複数のrowと複数のcolumnを指定
cars.loc[['IN', 'RU'], ['cars_per_cap', 'country']]
cars.iloc[[3, 4], [0, 1]]

項目を指定してセレクト

locとilocで項目を指定して全ての行をセレクトすることもできる(インデックスでの項目指定と同じように)

# 項目を指定して全ての行をSereisでセレクト
cars.loc[:, 'country']
cars.iloc[:, 1]

# 複数の項目を指定して全ての行をDataFrameでセレクト
cars.loc[:, ['country','drives_right']]
cars.iloc[:, [1, 2]]

Boolean Indexing

  • 複数条件を組み合わせる場合には()が必要な点に注意
 # trueとfalseのステートメントを使ってサブセットを取り出せる
 df[df['age'] >= 30]
 df[df['city'] == 'Tokyo']
 # 応用例。booleanのSeriesを作って、条件を満たすデータからソート。
 atleast_100 = movie_stats['rating']['size'] >= 100
 movie_stats[atleast_100].sort_values(by=[('rating', 'mean')],
                                     ascending=False)[:15]
                                     
 >>>football[(football.wins > 10) & (football.team == "Packers")]
    losses     team  wins  year
 3       1  Packers    15  2011
 4       5  Packers    11  2012 

その他ユースケース

nullが入っているデータ

isnullでnullが含まれているデータを検索できる

# nullの判定を実施
df['SAMPLE'].isnull()

# nullの行だけを抽出
df[df['SAMPLE'].isnull()]

Pandasで NaN (Null) の行だけ抽出

条件検索で複数の条件のどれかに合致

以下のようにisinを利用することでListの中の項目に一致するデータを抽出できる

(df[df['state'].isin(['NY', 'TX'])])

より高度な検索機能

# 条件の中で変数を使う
val = 80
df.query('point > @val')

# 複数条件を指定
df.query('age < 25 & point > 65')
df.query('age < 25 and point > 65')

nabetsunabetsu

4. データの削除、欠損値

  • dropで削除する
  • axis=1で列の削除であることを明示する
order_ts_dropped = order_ts.drop("TARGET_DATE", axis=1)

Pandas のデータフレームの特定の行・列を削除する

pandasデータフレームのデータの最後の行を削除する方法

欠損値の扱い

# NaNが1つでもある行を削除
df.dropna()
# 全ての列がNaNの行を削除
df.dropna(how='all')


# 項目を指定して対象項目がNaNの場合のみ除外
df.dropna(subset=['CHANNEL_KBN'])

pandasで欠損値NaNを除外(削除)・置換(穴埋め)・抽出

nabetsunabetsu

5. データの追加、変換

データの追加

新しい列名を指定することで項目を追加できる。

# Add total col as sum of individuals and family_members
homelessness['total'] = homelessness['individuals'] + homelessness['family_members']

# Add p_individuals col as proportion of individuals
homelessness['p_individuals'] = homelessness['individuals'] / homelessness['total']

# See the result
print(homelessness)

データタイプの変更

  • astypeでデータの変換が行える
s_f = s.astype('float64')
print(s_f)
# 0    13.0
# 1    23.0
# 2    33.0
# Name: c, dtype: float64

print(s)
# 0    13
# 1    23
# 2    33
# Name: c, dtype: int64

pandasのデータ型dtype一覧とastypeによる変換(キャスト)

条件分岐、ループ

  • forループとiterrows()を組み合わせることでDataFrameをループさせられる
    • 1つ目でラベル(インデックス)、2つ目で行全体にアクセスできる
    • ただし、iterationのたびに新しいSeriesを作ることになるので非効率
# Iterate over rows of cars
for lab, row in cars.iterrows():
    print(lab)
    print(row)
>>>
US
cars_per_cap              809
country         United States
drives_right             True
Name: US, dtype: object

# iterrowsを使って新しい項目を作ることもできる
# Code for loop that adds COUNTRY column
for lab, row in cars.iterrows() :
    cars.loc[lab, 'COUNTRY'] = row["country"].upper()
  • applyを使うことで行ごとに同じ関数を適用できる

pandasで条件分岐(case when的な)によるデータ加工を網羅したい

pandasで複数カラムをfor文で処理するときの高速化Tips

うわっ…私のpandas、遅すぎ…?って時にやるべきこと(先人の知恵より)****

1つの項目がインプット

1つの項目が対象であれば単純にapplyを実行すればOK。

# Responseという項目について、値がNoなら0、それ以外なら1を設定した項目を追加
df['Engaged'] = df['Response'].apply(lambda x: 0 if x == 'No' else 1)

上記の応用例でageという項目の値に応じてグループのラベルをつける例

df['age_group'] = df['age'].apply(
    lambda x: '[18, 30)' if x < 30 else '[30, 40)' if x < 40 \
        else '[40, 50)' if x < 50 else '[50, 60)' if x < 60 \
        else '[60, 70)' if x < 70 else '70+'
)

条件が細かくなるならlambdaではなく関数を定義してもOK

def func_cate(x):
    if  x < 10000:
        return 0
    elif x >= 10000 and x < 15000:
        return 1
    elif x >= 15000 and x < 19500:
        return 2
    else:
        return 3
stocks['cate'] = stocks['open'].apply(func_cate)

2つ以上の項目がインプット

DataFrameに対して処理を行い、尚且つapplyでaxis=1を指定する事で行を引数として渡す

def func_cate_change(x):
    if x.open < x.close:
        return 1
    elif x.open > x.close:
        return 2
    else:
        return 0
stocks['cate_change'] = stocks.apply(lambda x:func_cate_change(x),axis=1)

2つ以上の項目がインプットで高速に処理

pandasで複数カラムを参照して高速に1行1行値を調整する際のメモ

Categorical Dataの変換

  • Factorize
  • Categorical

Factorize

SeriesのFactorizeメソッドを使ってCategoricalデータの変換を行える。
ただし、数値の順序は指定できないので、順序が意味を持つケースでは使用できない。

gender_values, gender_labels = df['Gender'].factorize()
gender_values # array([0, 0, 0, ..., 1, 1, 1])
gender_labels # Index(['F', 'M'], dtype='object')

Categorical

pandasのCategoricalクラスを使えば順序を考慮してCategoricalデータを数値に変換できる

categories = pd.Categorical(
    df['Education'],
    categories=['High School or Below', 'Bachelor', 'College', 'Master', 'Doctor']
)

日付の取り扱い

以下のようにto_datetimeでフォーマットを指定してSeriesをまとめてdatetimeに変換できる

sales['pd_date'] = pd.to_datetime(sales['date2'], format='%m/%d/%Y')

pandasデータフレームの日付型⇄文字型変換とdfply使用時のメモ

Pythonでの日付処理まとめ(チートシート)

nabetsunabetsu

6. データの集計

集計関数(sum, count等)

sumcount等の集計関数を使ってDataFrameやSeriesの結果を集計できる。

引数でaxisの指定を行うことで集計対象を列か行か指定できる(axis=0(デフォルト)で列、axis=1で行)

> order_by_week.sum()
loginID
00076289    1473.0
0011C8B3       2.0
0013AF4C      13.0
0017472F      12.0
001D1FC7     229.0

> order_by_week.sum(axis=1)
TARGET_DATE
2020-03-11    269191.0
2020-03-18    211634.0
2020-03-25    275430.0
2020-04-01    252704.0
2020-04-08    243389.0

pandasで特定の条件を満たす要素数をカウント(全体、行・列ごと)

割合の算出

データフレームの値を割合に変更したいときはapplyを使って計算することができる

df_percent = temp_df.iloc[:, [0,1]].apply(lambda x: round(x / x.sum() * 100, 2), axis = 1)

列を持つピボットテーブルパンダのパーセンテージ計算

分析

ユニークなデータ数(ユーザの数とか)

uniqueの結果をshapeで表示することで分かる

JST_OrderManagement_His_df["loginID"].unique().shape

GROUP BY

ユーザごとの平均値など、グループ化した結果を取得したい時にはgroup byを使う。

# ユーザごとの平均評価点を求める
lens.groupby('user_id').mean()
# 映画ごとの平均評価点を求める
lens.groupby('movie_id').mean()
# ユーザごとに通番の番号をふる(0から始まるので+1する)
lens.groupby('user_id').cumcount()+1

# 全体に同じ関数を適用
>>> df.groupby('city').agg(np.mean)
price	quantity
city		
osaka	212.5	2.5
tokyo	250.0	6.0

# グループごとに適用する関数を指定
>>> df.groupby('city').agg({'price': np.mean, 'quantity': np.sum})
   price	quantity
city		
osaka	212.5	10
tokyo	250.0	18
# 同じグループに複数の関数を指定
>>> movie_stats = lens.groupby('title').agg({'rating': [np.size, np.mean]})
rating
size	mean
title		
'Til There Was You (1997)	9	2.333333
1-900 (1994)	5	2.600000

GroupByの流れ

  • groupbyの結果にはどんなメソッドでも渡せる
  • 渡したらそれがgroupbyの結果の各グループに適用される
decade = 10 * (planets['year'] // 10)
decade = decade.astype(str) + 's'
decade.name = 'decade'
planets.groupby(['method', decade])['number'].sum().unstack().fillna(0)

aggregate

filter

Groupbyとunstackの組み合わせ

unstackを活用することで行と列それぞれの対応関係を持つDataTableを簡単に作れる。

そのまま描画ができるので非常に便利。

age_marital_df = df.groupby(['age_group', 'marital'])['conversion'].sum().unstack('marital').fillna(0)

age_marital_df = age_marital_df.divide(
    df.groupby(
        by='age_group'
    )['conversion'].count(), 
    axis=0
)

Groupbyの結果を条件指定

groupbyした結果を条件つきカウントするには以下の方法でOK

df11=df.groupby('key1')['key2'].apply(lambda x: (x=='one').sum()).reset_index(name='count')

Pandas Dataframeでgroupbyの後に条件付きカウントを行う方法は?

Grouper

Grouperを使うことでpivot_tableやgroupbyを期間ごとの集計と組み合わせることができる

Python pandas アクセサ / Grouperで少し高度なグルーピング/集計

Pivot Table

多次元のgroup byと捉えればOK?

# groupby
titanic.groupby(['sex', 'class'])['survived'].aggregate('mean').unstack()
# pivot_table
titanic.pivot_table('survived', index='sex', columns='class')

以下のようにcutと組み合わせて分類した結果を項目にすることもできる
(第一引数が対象の項目、第二引数がインデックス、第三引数が項目?)

age = pd.cut(titanic['age'], [0, 18, 80])
titanic.pivot_table('survived', ['sex', age], 'class')

aggfunc

aggfuncでaggregationを実施する方法を指定できる(デフォルトはmean)

以下のように複数の項目を指定して、項目ごとに異なる集計を行うことも可能。

titanic.pivot_table(index='sex', columns='class',
                    aggfunc={'survived':sum, 'fare': 'mean'})

margins

margins=Trueを設定することで総計を表示することができる

titanic.pivot_table('survived', index='sex', columns='class', margins=True)

割合での表示

nabetsunabetsu

7. 時系列データ(Time-Series)

Datetimeの活用

  • Indexing by Time
    Datetimeをindexに設定すると以下のようにslicingで条件を指定できる他、resempleGrouper等、時系列分析に便利な関数が利用できる
index = pd.DatetimeIndex(['2014-07-04', '2014-08-04',
                          '2015-07-04', '2015-08-04'])
data = pd.Series([0, 1, 2, 3], index=index)
data['2014-07-04':'2015-07-04']

上記はDataFrame作成時に設定したが、既存の項目をインデックスに設定するにはrenameを利用すればOK。

order['TARGET_DATE'] = pd.to_datetime(order['TARGET_DATE'], format='%Y/%m/%d')
order_ts = order.rename(index=order['TARGET_DATE'])

日付で期間等を指定するにはdatetimeに変換してから抽出をすればOK

df['RecordDate_dt'] = pd.to_datetime(df['RecordDate'], format='%Y%m%d')
start = 20200311
end = 20200609

df.query('RecordDate_dt >= @start & RecordDate_dt <= @end')

上記でも意図した結果になると思われるが、datetime型で比較を行ったほうが良い?

df1[(df1['日付'] >= dt.datetime(2019,5,3)) & (df1['日付'] < dt.datetime(2019,5,6))]

年や月等の値へのアクセス

datetimeのデータの一部分にdataframe["column"].dt.componentの形式でアクセスできる。
componentはyearmonthのこと。

# 年にアクセス
df['date'].dt.year

# 月にアクセス
df['date'].dt.month

# 日付
df['InvoiceDate'].dt.date

pandasのDataFrameから期間を範囲指定して抽出する

resampleを利用した一定期間ごとの集計

以下のように時間をインデックスにしたDataframeはresampleで特定の期間ごとの値を集計できる

uri_df.iplot(title="注文金額推移(売り)")
kai_df.iplot(title="注文金額推移(買い)")

# 日次, 週次, 月次ごとの注文金額合計と注文頻度の推移
for symbol, name in zip(["D", "W", "M"],
                        ["日次", "週次", "月次"]):
    sum_df = pd.concat([uri_df.resample(symbol).sum(), 
                        kai_df.resample(symbol).sum()],
                       axis=1).fillna(0)
    print("注文合計額平均({})".format(name))
    print(sum_df.mean())
    sum_df.iplot(title="注文金額推移({}合計)".format(name),
                                     kind="spread")
    
    count_df = pd.concat([uri_df.resample(symbol).count(), 
                          kai_df.resample(symbol).count()],
                         axis=1).fillna(0)
    print("注文頻度平均({})".format(name))
    print(count_df.mean())
    count_df.iplot(title="注文頻度推移({}合計)".format(name),
                   kind="spread")

display(df)   

また、resampleを使った集計を行えば、指定した期間内でデータが存在しない日をゼロとして集計することができる(可視化に便利)


pd.DataFrame(extracted_df['count']).resample('D').sum()

shiftの活用

shiftを使うことで、行や列をずらすことができる。

# 元データ
data_resample
>>>
	BRK-A	^GSPC
Date		
2009-12-31	99200.000000	1115.099976
2010-01-31	102636.315789	1123.581582

# shiftの結果
data_resample.shift(1)
>>>
    BRK-A	^GSPC
Date		
2009-12-31	NaN	NaN
2010-01-31	99200.000000	1115.099976

# shiftと組み合わせて変化率の取得
np.log(data_resample/data_resample.shift(1))
>>>
 	BRK-A	^GSPC
Date		
2009-12-31	NaN	NaN
2010-01-31	0.034054	0.007577
2010-02-28	0.109991	-0.031115

pandasでデータを行・列(縦・横)方向にずらすshift

diffpct_changeでも差分を取得できるらしい。

pandasで行・列の差分・変化率を取得するdiff, pct_change

Grouperの活用

datetimeのデータに対してpd.Grouperを使うことで特定の期間単位での集計が簡単にできる。

# groupbyに適用するケース
df.groupby(pd.Grouper(freq='2W')).count()

# pivot_tableに適用するケース
df.pivot_table(index=pd.Grouper(freq='2W'), columns='label', aggfunc={'id': 'count'})
nabetsunabetsu

9. ユースケース

DataFrameをループ

iterrows()で縦のループ、iteritems()で横のループができる。
イテレートされるデータの型は'<class 'pandas.core.series.Series'>'

for index, x_data in x.iterrows():
     point = 0
     if x_data[10910] > 0:
         point += 0.5
         
     if x_data[10940] > 0:
         point += 0.5
         
     if x_data[10960] > 0:
         point += 0.5
     
     if x_data[11000] > 0:
         point += 0.5
         
     # x_data['target'] = point
     x.loc[index,'target'] = point
     print(index, x_data['target'])

縦持ちから横持ちへの変更

pivot_tableを使えば縦もちを横持ちに変換できる

df_7203.pivot_table(values=['value'], index=['base_date'], columns=['Tag_Summary'], aggfunc='sum')

Python: PandasのDataFrameを横持ち・縦持ちに変換する

行を一つずらす

shift()をつかって実現できる。
DataFrameにもSeriesにも適用でき、デフォルトでは1つ下にずれるので、
1つめの要素はNaNになる

import pandas as pd

>>> df = pd.DataFrame({'a': range(1, 6),
                       'b': [x**2 for x in range(1, 6)],
                       'c': [x**3 for x in range(1, 6)]})
>>> df
	a	b	c
0	1	1	1
1	2	4	8
2	3	9	27
3	4	16	64
4	5	25	125

>>> df['shift'] = df['a'].shift().fillna(0)
>>> df
	a	b	c	shift
0	1	1	1	0.0
1	2	4	8	1.0
2	3	9	27	2.0
3	4	16	64	3.0
4	5	25	125	4.0

pandasでデータを行・列(縦・横)方向にずらすshift

SQLの取得結果からDF作成

import pandas as pd
import pandas.io.sql as psql
 
connect = mysql.connector.connect(
     user=user, password=password, host=rdshost, db=db_name)
 
sql = 'SELECT * From Edinet_Api_Return'
data = psql.read_sql(sql, connect)

[実装備忘録] Python3のpandasでMySQLにアクセスする方法

データの先頭数文字の条件を指定

  • typeという項目の先頭1文字が1のデータのみを抽出
    • .astype(str)でデータ型を文字列に変換
    • .str[:1]で文字列の先頭1文字を抽出
order = order[order['type'].astype(str).str[:1] == '1']

最後の行を削除

.rptファイルで最後の行に「〜行処理されました」等入っていて削除したいケースを想定。

# 最後以外の行を抽出
df = df[:-1]

# 最後の行を削除
df.drop(df.tail(1).index)

pandasデータフレームのデータの最後の行を削除する方法

集計(期間 + id等)

pivot_tableでクロス集計するしかない?
groupbyでMultilevel indexを作ることもできる?

f = df_group.pivot_table(index=pd.Grouper(key="約定年月日",freq="6M"),
               columns='no', values='約定金額', aggfunc='count').fillna(0)

また、pivot_tableの時にindexとvaluesで同じキーは指定できない?
以下の通りエラーが出る。

def max_day(p):
    return max(p)

# KeyErrorになる
df_group.pivot_table(index=pd.Grouper(key="約定年月日",freq="6M"),
           columns='no', values='約定年月日', aggfunc=max_day)
>>>
KeyError['約定年月日']


# こっちはうまくいく
df_group['約定年月日_temp'] = df_group['約定年月日'] 
df_group.pivot_table(index=pd.Grouper(key="約定年月日",freq="6M"),
           columns='no', values='約定年月日_temp', aggfunc=max_day)

pandas apply関数の行のインデックスを取得する

pandas pivot_tableの引数aggfuncについて

日付の差分を数値に変換

datetime同士の演算で日数の差(間隔)を求めようとすると単位がdays(datetime)になってしまう。単位をintに直したいときはdatetimeのプロパティにアクセスしてdt.daysでintを求められる。

df['days'] = (df['date'] - today).dt.days

Pythonで経過時間や日時(日付・時刻)の差分を測定・算出

日付の間隔を数値型に変換

MultiindexのJoin

Joinは自動でindex同士の結合を行うので、indexの形式があっていればmultiindexでも結合ができる

f_multi = pd.DataFrame(f_score.stack()).rename(columns={0: 'F'})
m_multi = pd.DataFrame(m_score.stack()).rename(columns={0: 'M'})
r_multi = pd.DataFrame(r_score.stack()).rename(columns={0: 'R'})

temp = m_multi.join(f_multi)
temp = temp.join(r_multi)

MultiIndexを持つデータフレーム同士の結合