Pythonバイオ? 
162   2019-11-15 (金) 13:26:29

pandasティップス

行選択と列選択

行位置選択

行の値選択、列の値選択

セル選択

行演算と列演算

2列間での演算

Pandasで複数の列を値をもとに、新しい列を任意の関数で定義する方法 | Shikoan's ML Blog

import pandas as pd
comike = pd.DataFrame({
    "block" : ["AX", "AY", "あZ", "あX", "イQ", "イR"],
    "number" : [1, 1, 10, 11, 12, 13],
    "side" : ["aX", "bX", "aY", "bZ", "aQ", "bR"]
})
print(comike)
#comike["space"] = comike.apply(lambda x: f"{x['block']}-{x['number']:02d}{x['side']}", axis=1)
comike = comike[comike.apply(lambda x: x['block'][1]==x['side'][1], axis=1) ]
print(comike)

値・行名/列名でソートする

pandas.DataFrame, Seriesをソートするsort_values, sort_index | note.nkmk.me

値でソートする

df.sort_values()
df.sort_values(ascending=False)

行名でソートする

df.sort_index()

列名でソートする

df.sort_index(axis=1)

ifのある内包

even_list = [i for i in range(10) if i % 2 == 0]
even_list = [i if i % 2 == 0 else "odd" for i in range(10)]

三項演算子(条件式)

Pythonの三項演算子(条件演算子)でif文を一行で書く | note.nkmk.me
6. 式 (expression) — Python 3.8.0 ドキュメント 6.12. 条件式 (Conditional Expressions)

result = a * 2 if a % 2 == 0 else a * 3

elifを含めたい時(推奨せず)

result = 'negative' if a < 0 else 'positive' if a > 0 else 'zero'

要素データの置き換え replace

pandas.DataFrame, Seriesの要素の値を置換するreplace | note.nkmk.me

df = df.replace(oldvalue, newvalue)

列名の付け替え rename

pandas.DataFrameの行名・列名の変更 | note.nkmk.me

df = df.rename(columns={旧名: 新名, 旧名2: 新名2, ...})

インデックスの付け替え drop_indexとset_index

[[pandas.DataFrame, Seriesのインデックスを振り直すreset_index | note.nkmk.me https://note.nkmk.me/python-pandas-reset-index/]]

df = df.drop_index()  # インデックスは新たに列として加えられる。もし列名が重複するとエラー
df = df.drop_index(drop=True)  # インデックスを完全に削除(列として残さない)
df = df.set_index('列名')  # 列名の列をインデックスとして使う。その列は消える
df = df.reset_index.set_index('列名') # 元のインデックスを列として残しつつ変更

列位置の入れ替え

df = df.loc[:, ["col3", "col1", "col2", "col0"]]

行・列のdrop

pandas.DataFrameの行・列を指定して削除するdrop | note.nkmk.me

df = df.drop('行名', axis=0)   # axis=0はデフォルト
df = df.drop(index='行名')
df = df.drop('列名', axis=1)
df = df.drop(column='行名')

複数行・列の場合

df = df.drop(index=['行名1', '行名2']

行番号で指定

df = df.drop(index=df.index[1, 3, 5]))

なお、値を条件にして行を削除/残すのは、

df = df[df['参照']>=3]
df = df[(df['参照1']>=3) and (df['参照2']!='')]

でできる。

列名が重複してしまった時の列の削除

import pandas as pd
df = pd.DataFrame([['A',1, 0.1], ['B', 2, 0.2], ['C', 3, 0.3], ['D', 4, 0.4]], 
columns=['ラベル', '値', '値'])
print(df)
#  ラベル  値    値
#0   A  1  0.1
#1   B  2  0.2
#2   C  3  0.3
#3   D  4  0.4

dfx = df[['ラベル', '値']]    # 値は2つ残る
print(dfx)
#  ラベル  値    値
#0   A  1  0.1
#1   B  2  0.2
#2   C  3  0.3
#3   D  4  0.4

dfx = df.drop('値', axis=1)   # 2つともdropする
print(dfx)
#  ラベル
#0   A
#1   B
#2   C
#3   D

dfx = df.drop(df.columns[[2]], axis=1)  # 位置2を指定しても2つともdropする
print(dfx)
#  ラベル
#0   A
#1   B
#2   C
#3   D

dfx = df.copy()   # 浅いコピーだと列名書換えはdfの方にも及ぶので注意
dfx.columns = ['ラベル', '値', '値2']   # すべて指定すれば列名はすべて書き変えられる
dfx = dfx[['ラベル', '値']]   # 値2をdropすればいい
print(dfx)
#  ラベル  値
#0   A  1
#1   B  2
#2   C  3
#3   D  4

dfx = df.rename(columns={'値': '値3'})  # 両方とも書き換えられる
print(dfx)
#  ラベル  値3   値3   <-- 両方とも'値3'になるのでダメ
#0   A   1  0.1
#1   B   2  0.2
#2   C   3  0.3
#3   D   4  0.4

結論として、列名を全面的に書換えするしかなさそうだ。

DataFrameから辞書

pandas.DataFrame, Seriesを辞書に変換(to_dict) | note.nkmk.me

DataFrameの2つの列の間の関係を辞書にするためには、

Series/DataFrameからリストに変換するなら to_list()

pandas.DataFrame, SeriesとPython標準のリストを相互に変換 | note.nkmk.me

Seriesの値部分だけなら

s = pd.Series([0, 1, 2])
l_1d = s.values.tolist()

DataFrameの値部分だけなら

df = pd.DataFrame([[0, 1, 2], [3, 4, 5]])
l_2d = df.values.tolist()
print(l_2d)
# [[0, 1, 2], [3, 4, 5]]

行ラベル(行名)ともリストに変換するには、結局reset_indexとかでインデックスを列に含める

l_1d_index = s_index.reset_index().values.tolist()
print(l_1d_index)
# [['row1', 0], ['row2', 1], ['row3', 2]]

列ラベル(列名)はreset_indexに相当する機能が無いので、1つの方法として転置してからreset_indexをかける。

l_2d_index_columns = df_index.reset_index().T.reset_index().T.values.tolist()
print(l_2d_index_columns)
# [['index', 'col1', 'col2', 'col3'], ['row1', 0, 1, 2], ['row2', 3, 4, 5]]

ラベルだけなら、df.index、df.columnsだが、リストにするためにtolist()しておく

df.index.tolist()
df.columns.tolist()

重複した行をdropする

duplicatedとdrop_duplicates

df = df.duplicated(keep='last', subset=['この列での重複']) # 重複ならTrue、ないならFalseの1列
df = df[~df.duplicated(keep='...', subset=['..', '..'])]  # 重複以外をひろう(=drop_duplicates)

df = df.drop_duplicates(keep='last')  # 重複した列を最後の1つだけ残して削除

文字列を含む行の抽出

pandasで特定の文字列を含む行を抽出(完全一致、部分一致) | note.nkmk.me

完全一致は == でよい。

dfx = df[df['state'] == 'CA']

部分一致は、in はダメらしい。str.contains() を使う。

dfx = df[df['name'].str.contains('li')

但し、デフォルトでは第1引数を正規表現と解釈する(要するにre.searchと同様)ので、 ピリオド等を含む場合には正しくない。回避するためには regex=False を指定するとよい。

dfx = df[df['name'].str.contains('li', regex=False)

また、要素が欠損値NaNである場合、デフォルトではNaNを返すので、行を抽出するとエラーになる。オプションとして na=True/False を指定する。

dfx = df[df['name'].str.contains('li', na=True)]   # NaNは抽出結果に含まれる
dfx = df[df['name'].str.contains('li', na=True)]   # NaNは抽出結果に含まない

なお、str.containsの他、 str.startswith や str.endswidth 更に str.match(〜re.matchと同様の動作) が使える。

要素が指定リストに含まれる行の抽出 (文字列ではなくてリスト)

[[pandas.DataFrameの行を条件で抽出するquery | note.nkmk.me: https://note.nkmk.me/python-pandas-query/]]

基本的に、isinメソッドを使うか、queryメソッドの中で in を使うか。

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

dfx = df.query('state in ["NY", "TX"]')

これも可:

dfx = df.query('state == ["NY", "TX"]'

Groupby

pandas.DataFrameをGroupByでグルーピングし統計量を算出 | note.nkmk.me

grouped = df.groupby('グループ化したい列名')

この結果に対して統計演算ができる

df = grouped.sum()

使えるのはsum(), mean(), min(), max(), std(), var()など

また、agg()を使って、関数を適用することができる。関数はSeriesを受け取って objectを返す関数でなければならない。

df = grouped.agg(lambda x: type(x))['sl'])
df = grouped.agg(min)

列ごとに異なる関数を適用することも可能。

df = grouped.agg({'列1': min}, {'列2': max})

複数の列をキーにしてグループ化できる。

gf = df.groupby(['列1', '列2']).mean()

as_index=Falseを指定すると(True時はキーが結果DFのインデックスになるが)、キーは結果DFの行のままで残りインデックスは元のまま

df = pd.DataFrame({
    'city': ['osaka', 'osaka', 'osaka', 'osaka', 'tokyo', 'tokyo', 'tokyo'],
    'food': ['apple', 'orange', 'banana', 'banana', 'apple', 'apple', 'banana'],
    'price': [100, 200, 250, 300, 150, 200, 400],
    'quantity': [1, 2, 3, 4, 5, 6, 7]
})

gb = df.groupby(['city', 'food']).mean()  # as_index指定なし(デフォルトはTrue)
print(gb)

に対して

               price  quantity
city  food                   
osaka apple   100.0       1.0
      banana  275.0       3.5
      orange  200.0       2.0
tokyo apple   175.0       5.5
      banana  400.0       7.0

だが、as_index=Falseにすると

gb_noindex = df.groupby(['city', 'food'], as_index=False).mean()
print(gb_noindex)

に対して

     city    food  price  quantity

0  osaka   apple  100.0       1.0
1  osaka  banana  275.0       3.5
2  osaka  orange  200.0       2.0
3  tokyo   apple  175.0       5.5
4  tokyo  banana  400.0       7.0

のようにcityとfoodの列が残る。

Groupbyのグループを取出す

Pandas の groupby の使い方 - Qiita

df.groupby('city').groups

{'osaka': Int64Index([0, 1, 2, 3], dtype='int64'),
 'tokyo': Int64Index([4, 5, 6], dtype='int64')}

df.groupby('city').get_group('osaka')

city	food	price	quantity
0	osaka	apple	100	1
1	osaka	orange	200	2
2	osaka	banana	250	3
3	osaka	banana	300	4

df.groupby('city').size()

city
osaka    4
tokyo    3
dtype: int64

df.groupby('city').size()['osaka']

4

map, apply

pandasで要素、行、列に関数を適用するmap, applymap, apply | note.nkmk.me

複数dfをjoin

reference

DFのリスト joinlist = [df1, df2, ..., dfn] を用意し、dfにjoinする。

dfout = df.join(joinlist)

このとき、キー指定("on"の指定)はできない。インデックスをキーにしてjoinする。

つまり、あらかじめインデックスを付け替えておく必要がある。

df1 = df1.set_index('column to use as key')

NaN扱い

NaNはnumpyのnan

DFでなければ

if np.isnan(np.nan):
    hogehoge

DFでのnan判定

Reference→API reference のgeneral functionにある

df = pd.DataFrame8{[1,3],[2,np.nan]])
print(df.isnull())
print(df.notnull())

なお、isnull()はisna()のalias、notnull()はnotna()のalias

初めに空のDataFrameを作って後からデータ行を足す

df = pd.DataFrame( columns=['A', 'B'] )
for u in [0, 1, 2, 3]:
    temp_series = pd.Series( [i, i*i], index=df.columns )
    df = df.append( temp_series, ignore_index=True )

read_csvとto_csv

read_csv

pandasでcsv/tsvファイル読み込み(read_csv, read_table) | note.nkmk.me
pandas.read_csv — pandas 0.25.0 documentation
codecs — Codec registry and base classes — Python 3.7.4 documentation

import pandas as pd
pd.read_csv('filename', sep='\t', header=0, skiprows=[], encoding='cp932')

または

with open('filename', 'r', encoding='...') as fin:
    pd.read_csv(fin, ... )

なお、separatorが複数空白を含むとき、

pd.read_csv('filename', sep='\s+')

が使える。python - How to make separator in pandas read_csv more flexible wrt whitespace? - Stack Overflow

to_csv

df = ...
df.to_csv('filename', ...)

read_excelとto_excel

pandas.DataFrame.to_excel — pandas 0.25.0 documentation

If you wish to write to more than one sheet in the workbook, it is necessary to specify an ExcelWriter object:

>>> df2 = df1.copy()
>>> with pd.ExcelWriter('output.xlsx') as writer:  # doctest: +SKIP
...     df1.to_excel(writer, sheet_name='Sheet_name_1')
...     df2.to_excel(writer, sheet_name='Sheet_name_2')

ヒストグラム

散布図

ヒートマップ

階層的クラスタリング

import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage
from scipy.spatial.distance import pdist
import matplotlib.pyplot as plt
X = np.array([[1,2], [2,1], [3,4], [4,3]])
Z = linkage(X, 'single')  # ward法を使うならば 'single' の代わりに 'ward' を指定する
dendrogram(
    Z,
    leaf_font_size=8.,  # font size for the x axis labels
)
plt.show()
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import linkage, dendrogram
df_count_tpm = pd.read_csv("count_tpm.tsv", sep="\t", index_col=0)
tpm_t = df_count_tpm.T
print(df_count_tpm.head())
from scipy.spatial.distance import pdist
linkage_result = linkage(tpm_t, method='average', metric='correlation')
plt.figure(num=None, figsize=(16, 9), dpi=200, facecolor='w', edgecolor='k')
dendrogram(linkage_result, labels=df_count_tpm.columns)
plt.show()

k-means法によるクラスタリング

mySQLアクセス

def read_db(query):
    engine = create_engine('mysql+mysqldb://userid:password@localhost/dbname?charset=utf8',\
                           echo=False)
    dfr = pd.io.sql.read_sql(query, engine)
    return(dfr)

query = 'select * from tablename'
df = read_db(query)

ファイルの存在

import os
path = "./sample"
os.path.exists(path)

pickle

with open(picklefname, 'rb') as pf:
    df = pickle.load(pf)
with open(picklefname, 'wb') as pwf:
    pickle.dump(df, pwf)

条件式(3項演算子)

x = "OK" if n == 10 else "NG"

文字列のリストを繋いで1つの文字列にする

s = ''
for u in list:
   s += u

'間に挿入する文字列'.join([連結したい文字列のリスト])

s = ''.join(list)

文字列の検索

>>> "spam".find("pa")
1
>>> "spam".find("x")
-1

indexは見つからないときにエラーを返す

Seriesに2引数の関数をapplyする場合

df.x.apply(f1, args=(2,))
# または、 apply にキーワード引数で与える
df.x.apply(f1, b=2)

DF内の検索

df[X].isin([list])  listでなければならない。

pandasで任意の位置の値を取得・変更するat, iat, loc, iloc

https://note.nkmk.me/python-pandas-at-iat-loc-iloc/

argv, argc

import sys
argvs = sys.argv;
argc = len(argvs)
if (argc != 2):
    print('Usage: python %s filename' % argvs[0])
    quit()

リストのソート

newls = sorted(list)

メソッドsortはin-placeでソートするので注意。

list.sort()  # listそのものが置き換わる

グローバル変数

https://uxmilk.jp/12505

var = 1
def add_ten(x):
    global var
    var = 10
    print var + x
 
add_ten(2)    # 12
print var     # 10

リストの差分

https://python.ms/sub/optimization/if-vs-try/list-deletion/#_6-1-1-%E6%AF%94%E8%BC%83%E5%AF%BE%E8%B1%A1

def subtract_list(lst1, lst2):
    lst = lst1.copy()
    for e2 in lst2:
        try:
            lst.remove(e2)
        except ValueError:
            continue
    return lst

ifでチェックするより早い

型のチェック

特にNaNがあると、NaNはfloat型だと思い込むので、後の処理でぶつかることがある。

その時に、型チェックで逃げるとすると、(pandas的には個別の型チェックよりはdropnaなどの方がいいと思うが)必要になる。

Pythonで型を取得・判定するtype関数, isinstance関数 | note.nkmk.me

なのだが、isinstance()の方がよさそうだ。typeで引っかかない場合がある。

列の型変換

df['innings'].astype(np.int64)

リストの任意の位置への項目挿入

list.insert(位置, 値)

リストを置き換えるので注意

絶対値 pythonのabsとmathのfabs、numpyのabs(absolute)、fabs

pythonのabsは、整数の絶対値は整数、小数の絶対値は小数、複素数の絶対値も可。

mathのfabsは、整数に対しても小数に対しても、絶対値は小数を返す。複素数は不可。

numpyのabs(=absoluteと書いてもいいらしい)は配列ndarrayに対しても適用できる。 もし整数と小数が混ざっていると、小数にする(最大精度)。

numpyのfabsはmathのfabsと同様に、必ず小数を返す。複素数は不可。

ヒストグラム・カウント

df.hist()
(df['column']).hist()
(df['column']).value_counts()
(df['column']//10*10).value_counts()

カウント結果はSeriesなので、

s = pd.Series([3, 2, 7, 2, 3, 4])
u = s.value_counts(sort=False)
print(u)
# 2    2
# 3    2
# 4    1
# 7    1

print(type(u))
<class 'pandas.core.series.Series'>

print(u.index)
Int64Index([2, 3, 4, 7], dtype='int64')

# カウント結果uをindexでソートすると(黙っていると値の降順でソート)
print(u.sort_index(ascending=False))
# 7    1
# 4    1
# 3    2
# 2    2

〜〜〜〜〜〜〜〜〜〜〜〜

おまけ bashのループ

#!/usr/bin/bash
samples=("Anc" "1_2-1" "2_2-1" "2_5-1" "2_5-1-7A" "1_2-2" "2_2-2" "2_6-2" "2_6-2-10E")
for f in "${samples[@]}"
do
  #nohup python ProcessGD.py $f > $f.out &
  echo $f
done

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-11-15 (金) 13:26:29 (2d)