インポート
インポート
import pandas as pd
ついでに、下記もインポートしておく
(データフレームを表示する際にprintを使うよりdisplayを使うほうがきれい)
from IPython.display import display
データ確認
データ確認
# 先頭の5行を表示
print(df.head(5))
# 最後尾の5行を表示
print(df.tail(5))
# dataframe形式の表のレイアウトで表示
display(df)
DataFrame
DataFrame
空のデータフレーム
# 空のデータフレーム
df = pd.DataFrame(index=[], columns=[])
df = pd.DataFrame(index=[], columns=range(15))
df = pd.DataFrame(0,index=range(4), columns=range(15)) # 0で埋める
# 既存データフレームから空のデータフレームを作成
df_blank = df.iloc[0:0]
列(Columns)名置き換え
# カラム名を連番に置き換え (forで加工しやすいので)
df.columns=list(range(len(df.columns)))
# カラム名をアルファベットに置き換え (Excelと整合しやすいので)
df.columns=([chr(ord('A') + i) for i in range(26)]+["AA"]+["AB"])
行(Index)名振り直し
# indexを0から振り直す
df=df.reset_index()
df=df.reset_index(drop=True)
# indexを1から振り直す (Excelと整合しやすいので)
df.index = df.index + 1
# indexとは別の行に連番を振る
serial_num = pd.RangeIndex(start=0, stop=len(df.index) , step=1)
df['No'] = serial_num
列(Columns)加工
列加工
列抽出
df['A']
df=df[["F","Z"]]
# 任意の列だけ表示
df[['列名']]
# 1,2,4 行目
df.iloc[[1,2,4]]
# 0-2 列目
df.iloc[[0,2]]
列追加
# ない列を指定すると列が追加される
df['job'] = ["Engineer"]
df['new_column'] = 0 # 初期値を0で埋めて追加
条件抽出
df=df[df['A'] > 450]
df=df[df['A']=='P1']
# 複数条件指定
【注】(and、or、not)の替わりに(&、|、~)を使わないとエラーとなる
【注】比較演算子を使うときは条件ごとに括弧で囲まないとエラーとなる
df=df[(df['D']==0.0) | (df['D']==0.1)]
条件代入
# x=0 → y x<>0 →x
dfsum["z"]=dfsum["y"].where(dfsum["x"] ==0, dfsum["x"])
# 代入
gf2["打率"]=gf2['安打']/gf2['打数']
列名変更
# y を sales に変換
df.rename(columns={'y': 'sales'}, inplace=True)
df.columns = ['year_orig', 'pop', 'rate', '%']
列削除
# 列の場合はaxis=1が必要(デフォルトはaxis=0を行指定)
df.drop(['remarks'], axis=1, inplace=True)
# 列の内容の重複を排除
df=set(df2.A列)
列の値代入・更新
df['A'].apply(lambda x: x * 2) # =A1*2
df['A'].apply(lambda x: 1 if x>0 else 0) # IF(A1>0,1,0)的
スライス
# expand=Trueがあると、2つに分割してくれるが、ないとリスト形式内で分割される
print(df['a'].str[:2],expand=True)
タイプ変更
# 最初はobject型になっている
df=df.astype(float)
df1["G"]=df1["G"].astype(int)
オプション | 説明 |
---|---|
inplace=True | 破壊的変更となり、元データも変更になる |
行(Index)加工
行加工
【注】0から始まるので、Excel行-1となる
行抽出
# 特定の区間の行を抽出する
df[1:3]
# 100の行だけ抽出
df.loc[100]
# 100行目から105行目まで抽出
df[100:106]
# 最初の10行だけ抽出
df[:10]
行追加
ない行を指定すると行が追加される
df.loc['ONE'] = 0
# 行ごとに値追加
df.loc['FIVE'] = ['A5', 'B5', 'C5']
record = pd.Series([VD0,VD1], index=df2.columns)
df2 = df2.append(record, ignore_index=True)
行削除
df=df.drop(range(0,3))
df.drop(range(0,3),inplace=True )
置換
置換
df['col1'] = df['col1'].str.replace('x', 'z')
# 複数一括
df['col1']= df['col1'].replace({0:-1,1:-2,2:-3})
結合
結合
# 縦結合
df=pd.concat([df, df1])
# 横結合
df=pd.concat([df, df1], axis=1)
【注】Indexが異なると、真横に結合されないので、真横につけたい時はIndexを振り直す
マージ
マージ
dfsum=pd.merge(dfsum, gf2,on='キー',how="outer")
・「on」--- 明示的に結合するキーを指定
複数指定可能 on=['keyA', 'keyB']
・how」-- 結合方法を指定
inner -- 両方のデータフレームのキーがあるもののみ
left -- 左のデータフレームに。右のデータフレームの情報が付加され、不足はNaN
right -- 右のデータフレームに。左のデータフレームの情報が付加され、不足はNaN
outer -- 両方のデータフレームのすべてのキーを選択。不足情報はNaN
グループ
グループ
gf = df3.groupby('選手名')
gf1=gf.agg({'本塁': max,'盗塁':'max','打率':'max'})
セル
セル
# 指定 (atの方が早いらしい)
df.loc[333,'bbb'] #df.loc['行名','列名']
df.iloc[2,1] #df.iloc['行番号','列番号']
df.at[333,'bbb'] #df.at['行名','列名']
df.iat[2,1] # df.at['行番号','列番号']
# 代入
df.loc[99,0] ='▲'
df.loc[:, 2:8] = 0
【注】df.loc[99][0]の書き方(chained indexing)だと、SettingWithCopyWarningが発生したり、
値がかわらなかったりする
# 値の条件抽出
VD0=df1.loc[((df1["D"]==0) & (df1["G"]==6)),"E"]
VD0=VD0.values.tolist()[0]
ソート
ソート
df.sort_values(['sales', 'temperature'], ascending=False)
sorted(df)
オプション | 説明 |
---|---|
ascending=True | 降順 |
ascending=False | 昇順 |
複製
複製
df1 = df.copy()
【注】df1 = dfにすると、参照渡しになるので、df1を変更するとdfも変わってしまう
変換
変換
# リスト → DataFrame
pd.DataFrame(data=list)
# データ部分 → リスト
s = pd.Series([0, 1, 2])
print(s)
# 0 0
# 1 1
# 2 2
# dtype: int64
list= s.values.tolist() # リストになる
V0=s.values.tolist()[0] # 値取出し
表示
表示
# カラム、Indexを表示しない
print(df.to_string(index=False, header=False))
既存のデータフレームを新しいデータフレーム分を更新する
既存のデータフレームを更新
(条件)
・既存データフレーム
NaNがある
新データフレームにない列がある
新データフレームにない行がある
・新しいデータフレーム
NaNがある
既存データフレームにない列がある
既存データフレームにない行がある
・更新条件
数字は大きい方を採用
文字は新しい方を採用
(結果)
いい方法が、見つからず。
下記のように、しましたが、いい方法がありましたら、御教授をお願いします
(手順)
・マージした後、ソートする
→これで行数、列数は自動調整される。但し、共通の列は2列にわかれたまま
df=pd.merge(dfA, dfB,on='A列',how="outer")
df=df.sort_values(['A列'], ascending=True)
・NaNを一旦、使用していない0に変換する
df1=df.fillna(0)
・数字のB列は、大きい値を採用
df1['B列'] = np.where(df1['B列_x']>df1['B列_y'], df1['B列_x'], df1['B列_y'])
・文字列のC列は新しい方を採用する
単純に上書きすると、既にある値をNaNにしてしまう可能性があるので、NaN=0でない場合のみ書き換える
df1['C列'] = np.where(df1['C列_y']!=0, df1['C列_y'], df1['C列_x'])
・列を元に戻す
df2=df1.reindex(columns=['A列', 'B列', 'C列', 'D列', 'E列'])
・0をNaNに戻す
df2 = df2.replace([0], np.nan)
別ファイルの列同士では、キーが合っていないので、一括では比較できない、そこで最初にマージして
キーを合わすことで、比較できようにした
ファイル読み込み・書き出し
ファイル読み込み・書き出し
Excelファイル読み込み
df = pd.read_excel('sample.xlsx',sheet_name='sheet1')
オプション | 説明 |
---|---|
sheet_name="" | シート名を指定 |
header=None | 指定するとヘッダなしで読み込む |
指定しないときは、1行目が自動的にカラム名として挿入される | |
header=2 | 指定行をヘッダとして読み込み。それ以前の行は無視される。これ以降から0行が始まる |
Excelファイル書き出し
df.to_excel('sample.xlsx',sheet_name='sheet1', encoding='cp932',index=False, header=False)
オプション | 説明 |
---|---|
sheet_name="" | シート名を指定 |
index=False | 行名を削除して書き出し |
header=False | 列名を削除して書き出し |
csvファイル読み込み
df=pd.read_csv("sample.csv",encoding="cp932",header=None)
df=pd.read_csv("sample.csv",encoding="shift_jis",header=False)
df1=pd.read_csv(sample.csv,encoding='cp932',names=col_names,low_memory=False )
【注】windows拡張文字列が混ざっている場合は、文字コードをcp932としてやる必要がある
【注】重たいファイル読み込む時はlow_memory=Falseを記載する
df = pd.DataFrame(index=[], columns=range(21))
col_names = ['c{0:02d}'.format(i) for i in range(21)]
df=pd.read_csv("myfile.csv",encoding="cp932", names = col_names)
【注】途中で列数が変わる場合、エラーになるので、事前に列数と仮の名前を設定しておく
csvファイル書き出し
df.to_csv('sample.csv',encoding='cp932',header=False)
TAB区切りファイル読み込み
df=pd.read_csv("sample.DAT",encoding='cp932', sep='\t',names=col_names)
テキストファイル読み込み
df=pd.read_table("sample.DAT",encoding='cp932',header=None)
テキストファイル書き込み
df.to_csv("employee.csv", sep=",",header=False)
欠如データ
欠如データ
# A列にあるNaNを'0.0'に置き換える
df.fillna(value={'A': 0.0}, inplace=True)
# A列にNaNがある行を削除する
df.dropna(subset=[A], axis=0, inplace=True)
# A列の '--' を 0に置き換える
df['A'] = df['A'].replace('--', 0).astype(float)
# NaNを上セルの値で埋める
df=df.fillna(method='ffill')
# 0をNaNに戻す
df = df.replace([0], np.nan)
可視化
可視化
import matplotlib.pyplot as plt
以下を実行するとプロットスタイルが変更されていい感じになる
plt.style.use('ggplot')
記法 | 操作の内容 |
---|---|
plt.title('グラフタイトル') | タイトルを設定 |
plt.xlabel('X軸ラベル') | x軸の名前を設定 |
plt.ylabel('Y軸ラベル') | y軸の名前を設定 |
plt.xlim(Xの最小値, Xの最大値) | x軸の範囲を指定 |
plt.ylim(Yの最小値, Yの最大値) | y軸の範囲を指定 |
plt.legend() | 凡例を表示 |
plt.grid() | グリッド線を表示 |
import random
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(index=[], columns=range(2))
df.columns=list(range(len(df.columns)))
for i in range(4):
df.loc[i] = [i ,2*random.random()]
print(df)
plt.plot(df[0],df[1])
plt.show()
メモリ節約
メモリ節約
不要な変数を削除して、メモリ解放する
delで不要な変数を削除する
del 変数
使用していないメモリを開放する
gc.collect()
不要なカラムを消す
del df['column1']
# または
df = df.drop(columns=['column1'], axis=1)
read_csvする場合は、必要なカラムだけを読み込む
df = pd.read_csv('file.csv', usecols=['column1', 'column2'])
必要レコードだけ抽出する
df = df.loc[df["id"] >= 100000]
copyの多用しない
df1 = df.copy() # copyした変数分のメモリが新規に消費されてしまう
df2 = df # 参照渡ししても問題ない場合はcopy()を使わない
破壊的代入する
既存の変数を変更する際、変数名を変えてしまうと、新しい変数ができてしまうので、
極力同じ変数名を使うようにします。
# 非破壊的な例
df3 = df1.loc[df1['id'] >= 10000]
df4 = pd.concat([df3, df2])
# 破壊的な例
df1 = df1.loc[df1['id'] >= 10000]
df1 = pd.concat([df1, df2])
mergeする際は、copy=Falseにする。
デフォルトだとTrueになっており、copyが生成され、メモリを必要以上に使用してしまう
df1 = df1.merge(df2, on='column1', how='left', copy=False)
カラムの型を指定
指定しないと自動でint64またはfloat64となってしまうので、必要分だけを指定する
df = df.astype(
{
"id": np.int32,
"status": np.int8,
"price": np.int32,
"weight": np.float32
}
)
read_csvする場合は、読み込み時点で型指定しておく
df = pd.read_csv(
"file.csv",
dtype={
"id": np.int32,
"status": np.int8,
"price": np.int32,
"weight": np.float32
}
)
メモリ使用量の確認方法
print(f"df memory usage: {df.memory_usage(deep=True).sum() / 1024 ** 2} MB")