Pythonバイオ? 
765   2020-03-31 (火) 15:27:23

pandasティップス

行選択と列選択

行位置選択

行の値選択、列の値選択

セル選択

行演算と列演算

行間での足し算

import pandas as pd
df = pd.DataFrame([['A', 1, 3], ['B', 2, 4], ['C', 3, 5], ['D', 4, 6]], \
                  columns=['a', 'b', 'c'])
print(df)
#   a  b  c
#0  A  1  3
#1  B  2  4
#2  C  3  5
#3  D  4  6

print(df[df.index.isin([2, 3])].sum())  # リストにある行を足す
#a    CD
#b     7
#c    11
#dtype: object

print(df.loc[0:1].sum())  # 連続した行を足す
#a    AB
#b     3
#c     7
#dtype: object

print(df.loc[[0,2]].sum()) # (リストにある)とびとびの行でもOK
#a    AC
#b     4
#c     8
#dtype: object

おまけ、平均

print(df[df.index.isin([2, 3])].mean())
#b    3.5
#c    5.5
#dtype: float64

print(df.loc[0:1].mean())
#b    1.5
#c    3.5
#dtype: float64

pandas DataFrameで数値の桁数を丸めるには

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, ...})

なお、indexに対する名前を付けるには

df.index.name = colname1

同様に、

df.columns.name = colname2

つまり

import pandas as pd
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['A','B','C'])
print(df)
df.index.name='インデックス'
print(df)
df.columns.name = 'カラム'
print(df)

とすると、何もつけないときは

   A  B  C
0  1  2  3
1  4  5  6
2  7  8  9

indexに名前'インデックス'を付けると

        A  B  C
インデックス         
0       1  2  3
1       4  5  6
2       7  8  9

更に、columnに名前'カラム'を付けると

カラム     A  B  C
インデックス         
0       1  2  3
1       4  5  6
2       7  8  9

となる。

インデックスの付け替え 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からリストに変換するなら .values.tolist()

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 )

あとから列を足すのは、縦のデータの長さが同じなら簡単で、上記の場合縦が4なので

df['NEW'] = [3, 4, 5, 6]

長さが異なる場合、上記の方法はエラーになる。Seriesを作って同じように書きこめばOK.

## Test 〜 convert list (with different length) to DF column
import pandas as pd
import numpy as np

list1 = [1, 2, 3]
list2 = [4, 5, 6, 7, 8]
list3 = [10, 11]

# リストの長さがすべて同じならば、単純にdf['新列名']=listでOK
# 長さが異なるとエラー
df = pd.DataFrame(index=[0, 1, 2, 3, 4], columns=[])
#df['A'] = list1  <-- 長さが違うのでエラー

s = pd.Series(list1, index=[0,1,2])
df['A'] = s
print(df)  # これだと、不足した要素部分はNaN
#     A
#0  1.0
#1  2.0
#2  3.0
#3  NaN
#4  NaN

df.to_excel('mytest.xlsx')  # NaNの場所はExcel上では空欄になる

df = df.replace(np.nan, '')  # nanを空文字列に置換え
print(df)
#   A
#0  1
#1  2
#2  3
#3   
#4   

df.to_excel('mytest2.xlsx')  # 空文字列の場所はExcel上では空欄になる

collections.Counterの結果を加える

[Python] リストの要素の数を数える (collections.Counter) | Hibiki Programming Notes

c1 = collections.Counter('abbcabbbccca')
c1.update({'a':1, 'b':1, 'c':1})   # c1を書き換えることに注意('+'と異なる)

または

c1 = collections.Counter('abbcabbbccca')
c1.update('abc')

もOK

引く場合は、subtract

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> d = Counter(a=1, b=2, c=3, d=4)
>>> c.subtract(d)   # cを書き換えることに注意('-'と異なる)
>>> c
Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

0やマイナスになり得る

また、8.3. collections --- コンテナデータ型 — Python 3.6.10rc1 ドキュメントでは

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # add two counters together:  c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d                       # intersection:  min(c[x], d[x]) 
Counter({'a': 1, 'b': 1})
>>> c | d                       # union:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})

引き算は0や負になると要素が消える(Countだから?)ので注意〜subtractと振る舞いが異なる。

基本的に、カウントが0の項目は削る方向に動く。従って、Counter同士を足したり引いたり した結果、値が0になればprintしても見えなくなる。

Counterはほぼ辞書と同じなので、次項のソートが使える。

辞書のソート

Pythonの辞書(dict)をソートする方法まとめ | HEADBOOST

d = {'b': 2, 'a': 3}
print(sorted(d)) # keyを取出してソート
print(sorted(d.keys())) # 上と同じこと
print(sorted(d.values()))
print(sorted(d.items())) # itemを取出してkey順でソート
print(sorted(d.items(), key = lambda x : x[1])) # itemを取出してvalue順でソート

これを使って、codons数を数えて出力をcodon名順にソート

import pandas as pd
import collections
# dict (codon count) をDFに書き込む
# d = {'B':1, 'C':2}
# df= pd.DataFrame(columns=['A', 'B', 'C'])
# 結果としてAは0, Bは1, Cは2と書いて欲しい

zerodic = collections.Counter([])  # これは不可 エントリーCが入らない
zerodic = collections.Counter({'A':0, 'B':0, 'C':0})
print(zerodic)  ## 意図は{'A', 0:, 'B': 0, 'C':0}
d = collections.Counter({'B':1, 'C':2})
print(zerodic+d)  # これは不可。カウントが0のエントリーCが入らない
#
zerodic.update({'B':1, 'C':2})  # updateだと元のzerodicがそのまま型紙になる
              # 但しupdateはin-placeで置き換えるので注意
print(zerodic)
# あとはキーでソートして値をリストにして、pd.Seriesに変換して、pd.DataFrameに追加
szero = sorted(zerodic.items(), key=lambda x: x[0])  # ペアでソート、出力はペアのリスト
szerolist = [u[1] for u in szero]  # 値だけのリストにする
print(szerolist)
ser = pd.Series(szerolist, index=df.columns)
df = df.append(ser, ignore_index=True)
print(df)

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')

to_excelで、セル内に改行を置きたい場合

デフォルトでは改行は不可(\nを入れても効果ない)

セルのスタイルプロパティで、wrap_text=Trueを設定する。

結局、to_excelでファイルを作ってしまってから、もう一度openpyxlでファイルをオープンして、 シート内のすべてのセルのプロパティを上記3番目で変更するのが簡単そう。

なお、変更の方法は、

cell.alignment =  cell.alignment.copy(wrapText=True)

はDepreciatedのwarningが出るので、

cell.alignment = Alignment(wrap_text=True)

にしてみた。

全体は、

# "to_Excel"でセル内改行アリが可能か?
import pandas as pd
df = pd.DataFrame([['5\n4' ,3], [2,6], [8,5]])   # データ中に\nを入れる
print(df)
df.to_excel("mytest2.xlsx")    # とにかくDFのデータからexcelファイルを作ってしまう

import openpyxl
from openpyxl.styles import Alignment
wb = openpyxl.load_workbook('mytest2.xlsx')
ws = wb['Sheet1']
for row in ws.iter_rows():
    for cell in row:      
        #cell.alignment =  cell.alignment.copy(wrapText=True) # Depreciated警告
        #cell.style.alignment.wrap_text=True    # エラー
        cell.alignment = Alignment(wrap_text=True)  # これなら動いた
wb.save('mytest2.xlsx')    # ファイルへ書き出し(書き戻し)

これによって実現できる。

ヒストグラム

散布図

散布図の各点に値を書く

matplotlibのannotateを使う

<Python, matplotlib> 散布図の各要素に文字を付ける。 - ねこゆきのメモ

Pandasで散布図を書くとき各要素のラベルを表示 - Qiita

annotateを使うのにaxが必要なので、たとえば、

%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame([[1,3,5], [2,4,6]], index=['助教', '教授'], columns=['少ない', 'まあまあ', '多い'])
dfx = pd.DataFrame(columns=['職階', '評価', '発生数'])
for ix in df.index:
    for col in df.columns:
        line = [ix, col, df.loc[ix][col]]
        s = pd.Series(line, index=['職階', '評価', '発生数'])
        dfx = dfx.append(s, ignore_index=True)
print(df)
print('dfx\n', dfx)
ax = plt.subplot(1,1,1)  # <-- このようにしてaxを作る
plt.scatter(dfx['職階'].to_list(), dfx['評価'].to_list(), s=[u*20 for u in 
dfx['発生数'].to_list()])

for k, v in dfx.iterrows():
    print(v)
    ax.annotate(v[2],xy=(v[0],v[1]),size=14)
plt.show()

Pandasで散布図を書くとき各要素のラベルを表示 - Qiitaではaxを作る代りに、

import pandas as pd

# DataFrameにデータをセット
dd = pd.DataFrame([
        [10,50,'hoge'],
        [50,30,'fpp'],
        [20,30,'baa']
    ], columns=['ax','ay','label'])

# 散布図を描画
a = dd.plot.scatter(x='ax',y='ay')
# 各要素にラベルを表示
for k, v in dd.iterrows():
    a.annotate(v[2], xy=(v[0],v[1]), size=15)

のように、a = df.plot.scatter() としておいて、このaに対して a.annotate()。

散布図で上記annotationを加えたときに文字が重なるのを防ぐ

いるかのボックス: Matplotlibでテキストラベルを重ならないように表示する

散布図で点のラベルを入れたときに、数が多いと、重なり合って読めなくなることがある。それを避けるには、adjust_textライブラリが使える。(adjustとtextの間に下線があったりなかったりなので要注意)

pip install adjusttext

でインストールした後、

from adjustText import adjust_text
...
texts = []
a = dfout.plot.scatter(x='重要度', y='満足度')
for k, v in dfout.iterrows():
    u = a.annotate(v[2], xy=(v[0],v[1]), size=10)
    texts.append(u)
plt.title('...')
adjust_text(texts)
plt.savefig(...)
plt.show()

これで、かなりの場合自動的に位置を決めてくれる。(但し遅くなるらしい)

ヒートマップ

階層的クラスタリング

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()

クラスター自体を取出したい時は fcluster が使える。

import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage, fcluster
from scipy.spatial.distance import pdist
import matplotlib.pyplot as plt
X = np.array([[1,2], [2,1], [3,4], [4,3], [1,3], [3,1]])
Z = linkage(X, 'single')  # ward法を使うならば 'single' の代わりに 'ward' を指定する
plt.figure(figsize=(20,20), dpi=200, facecolor='w', edgecolor='k')
dendrogram(
    Z,
    leaf_font_size=8.,  # font size for the x axis labels
    labels = ['A', 'B', 'C', 'D', 'E', 'F']
)
plt.savefig('dendrogram.pdf')
plt.show()

NUM_CLUSTERS = 5
nodelabels = ['A', 'B', 'C', 'D', 'E', 'F']
for num in range(5, NUM_CLUSTERS+1):
    labels = fcluster(Z, t=num, criterion='maxclust')
    #fclusterは、入力がどのクラスタに属するか(クラスタ番号 labels)を返す
    print(num, labels)
    # クラスタごとに、それに属する入力をリストとして表示
    for cl_id in range(1, num+1):
        l = [nodelabels[n] for n in range(0,len(labels)) if labels[n]==cl_id]
        print(' ', cl_id, l)

出力はtest_dendrogram.png

fclusterの出力:

5 [1 2 3 4 1 2]  # リストに各要素のクラスタid(1〜4)。第1要素と第5要素はクラスタ1に、第2と第6はクラスタ2に属する

それを書き直した結果:

  1 ['A', 'E']   # 上記を、クラスタ1には要素1と5が属すると変形し、更に要素id(1,5)をラベル(A,E)に置換えた
  2 ['B', 'F']
  3 ['C']
  4 ['D']
  5 []

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

プレーンなPythonの場合

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

PandasのDataFrameの場合、(メソッドがある)

df.to_pickle(picklefname)
df = pd.read_pickle(picklefname)

条件式(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そのものが置き換わる

リストのflatten

# Python 3 で flatten する方法いろいろ

# https://qiita.com/hoto17296/items/e1f80fef8536a0e5e7db

sum([[1,2,3],[4,5,6],[7,8,9]], [])  #=> [1, 2, 3, 4, 5, 6, 7, 8, 9]

グローバル変数

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と同様に、必ず小数を返す。複素数は不可。

pie chartで生のデータを入れる

python - Pandas pie plot actual values for multiple graphs - Stack Overflow

ヒストグラム・カウント

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

Pandasでデータの値の頻度を計算するvalue_counts関数の使い方 - DeepAge

カウント結果は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

matplotlibでsavefigしたときに下が切れる場合

Matplotlib (with seaborn) で出力するPDFの下のほうが切れてしまうときは bbox_inches='tight' - Scala日記

bbox_inches = "tight"とかそれ系のやつ - virsalusの日記

plt.savefig('sample.pdf', bbox_inches='tight')

とするか

plt.tight_layout()

とするかで対応。

距離行列dmatがあるとき、

ndmat =squareform(dmat)
lk = linkage(ndmat,method='average')
plt.figure(num=None, figsize=(22, 12), dpi=200, facecolor='w', edgecolor='k')
dendrogram(lk, labels=dmat.index, leaf_rotation=90)
plt.tight_layout()
# plt.savefig('corr_coeff_dendrogram.png', bbox_inches="tight")
plt.savefig('corr_coeff_dendrogram.png')

XML to Dict

Python: xmltodict を使って XML を辞書へ変換

biopython, SNP in feature

BioPython Tutorial

4.3.2.4 Location testing

You can use the Python keyword in with a SeqFeature or location object to see if the base/residue for a parent coordinate is within the feature/location or not.

For example, suppose you have a SNP of interest and you want to know which features this SNP is within, and lets suppose this SNP is at index 4350 (Python counting!). Here is a simple brute force solution where we just check all the features one by one in a loop:

>>> from Bio import SeqIO
>>> my_snp = 4350
>>> record = SeqIO.read("NC_005816.gb", "genbank")
>>> for feature in record.features:
...     if my_snp in feature:
...         print("%s %s" % (feature.type, feature.qualifiers.get("db_xref")))
...
source ['taxon:229193']
gene ['GeneID:2767712']
CDS ['GI:45478716', 'GeneID:2767712']

Note that gene and CDS features from GenBank or EMBL files defined with joins are the union of the exons – they do not cover any introns.

Matplotlibで、複数のfigureを1つのPDFファイルに保存する方法

matplotlibで複数のfigureを一つのpdfに保存する - Qiita

import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages  # <-- 追加

pdf = PdfPages('ファイル名.pdf')   # <-- 追加 (pdfをオープン)

for ... :   # 複数枚作る
    plt.scatter(....)    # plotして図を作る
    pdf.savefig()   #  <-- savefigの行先はpdfになる
    plt.show()    # <-- 画面表示

pdf.close()   # <-- 最後に忘れないように 

pandas plot.barでX軸目盛の文字が縦を向かない件

DataFrame df を df.plot.bar() でグラフ表示するとき、X軸目盛の文字が 横向きになってしまう。

いろいろやってわかったのは、

df.plot.bar(y='カラム名')

とすると正しく表示されるが、

df.plot.bar()

だとダメ。y=を書かないスタイルは、すべてのカラムが表示されるので具合がいい。 dfに1つしかカラムがなければそれで済むし、複数あればそれらがみな表示される。 ラベルのことさえ気にしなければこれでも十分だろう)

また、xticksを使って回転させるワザは働かなかった。たとえば

plt.xticks(rotation=90)

とかは効かなかった。

Seaborn heatmapで上下単が切れる問題

seabornのheatmapでy軸が足りなくて、annotが活用できない - Qiita

バージョンアップで解決。古いバージョンの時は逃げる方法がある。 ax.set_ylim(len(flights), 0)

Seaborn heatmapまわり

とりあえずマニュアル

seaborn.heatmap — seaborn 0.9.0 documentation

annotation

fmtの指定: fmt='.2f'とかfmt='d'とか

カラーパレット

Seabornのカラーパレットの選び方 - Qiita

Seabornで相関をヒートマップにする(行・列を並び替えながら) / Heatmap using Seaborn (order rows and columns as you like) - Qiita

seabornの細かい見た目調整をあきらめない - Qiita

annot_kws={'fontsize': 9, 'color': 'green'} とかできる。

連関係数の計算に使えるCrosstab

crosstab() — researchpy 0.1.1 documentation

PythonからPDFが書き出せるreportlab

ReportLab - Content to PDF Solutions

で、この辺が使えそう。

# reportlab platypus Tableを使う例
# reportlab の Table の表示位置をコントロールする
# https://qiita.com/ekzemplaro/items/09bd10b02ecbb35c0efa

from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import mm
from reportlab.lib import colors
from reportlab.lib.styles import ParagraphStyle
from reportlab.pdfgen import canvas
from reportlab.platypus import Image, Paragraph, Table
from reportlab.pdfbase import pdfmetrics
#from reportlab.pdfbase.cidfonts import UnicodeCIDFont
from reportlab.pdfbase.ttfonts import TTFont
# ------------------------------------------------------------------
#fontname_g = "HeiseiKakuGo-W5"
#pdfmetrics.registerFont(UnicodeCIDFont(fontname_g))
pdfmetrics.registerFont(TTFont('IPAexGothic', 'ipaexg.ttf')) 

cc = canvas.Canvas('example.pdf', pagesize=A4)
width, height = A4

cc.setFont("IPAexGothic", 16)
str_out = "こんにちは"
cc.drawString(100, 730, str_out)

data = [["テスト", 2, 3], ["日本語", 1, 3], [3, 2, 10]]

table = Table(data, colWidths=20*mm)
table.setStyle([("VALIGN", (0,0), (-1,-1), "MIDDLE"),
                ("ALIGN", (0,0), (-1,-1), "CENTER"),
                ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
        ('BOX', (0, 0), (-1, -1), 0.25, colors.black),
#        ('FONT', (0, 0), (-1, -1), "HeiseiKakuGo-W5", 16),
        ('FONT', (0, 0), (-1, -1), "IPAexGothic", 16),
        ])
#
table.wrapOn(cc, width, height)
#
table.drawOn(cc, 140*mm, 250*mm)
table.drawOn(cc, 75*mm, 225*mm)
table.drawOn(cc, 10*mm, 200*mm)
#
styles = getSampleStyleSheet()
my_style = styles["Normal"]
my_style.name = "bonlife"
#my_style.fontName = "HeiseiKakuGo-W5"
my_style.fontName = "IPAexGothic"
my_style.fontSize=16

ptext = "これはサンプルです。"
pp = Paragraph(ptext, style=my_style)
pp.wrapOn(cc, 70*mm, 50*mm)  # size of 'textbox' for linebreaks etc.
pp.drawOn(cc, 50*mm, 190*mm)    # position of text / where to draw

cc.showPage()
cc.save()
print('complete')

と、もっと簡易版で

# reportlab platypus Tableを使う例
# reportlabのplatypusを使ってtableを描画するサンプル。wrapOnを呼びなさいということ
#https://gist.github.com/bgnori/4452571
   
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

from reportlab.lib import colors
from reportlab.platypus import Table

#pdfmetrics.registerFont(TTFont('IPA Gothic',
#    '/usr/share/fonts/ipa-gothic/ipag.ttf'))
pdfmetrics.registerFont(TTFont('IPAexGothic', 'ipaexg.ttf'))

xmargin = 8.4*mm
ymargin = 8.8*mm
swidth = 48.3*mm
sheight = 25.4*mm

c = canvas.Canvas('example2.pdf', pagesize=A4)

#c.drawString(xmargin, ymargin, u"どや、pdfやで。reportlab!")

t = Table([['a', 'b'], ['1', '2']])
#t.setStyle([('TEXTCOLOR', (0,0), (1,0), colors.red)])  # 元サンプルではこうしている
t.setStyle([('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), # 罫線、上のサンプルから借用
        ('BOX', (0, 0), (-1, -1), 0.25, colors.black),
        ('FONT', (0, 0), (-1, -1), "IPAexGothic", 16),
        ])

t.wrapOn(c, 100*mm, 100*mm)

t.drawOn(c, 100*mm, 100*mm)
c.showPage()
c.save()
print('complete')

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

おまけ 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

添付ファイル: filetest_dendrogram.png 15件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2020-03-31 (火) 15:27:23 (3d)