Pythonのメモ帳

numpy, pandas, tensorflow を使いこなすための忘備録

pandas の append処理で行ラベル(index番号)がおかしくなった時に行ラベルをリセットする

pandas で append処理(2つのDataFrameを縦に連結)した時、行ラベル(index番号)は順番通りにならなくなる。

 例えばこう。

import pandas as pd
import numpy as np

data = range(10)
data = np.array(data).reshape([5,2])
df1 = pd.DataFrame(data,columns=['col0','col1'])
df2 = pd.DataFrame(data,columns=['col0','col1'])
df  = df1.append(df2)
print(df)

Out:

  col0 col1
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9

 

 

df.loc()など行ラベルを参照する処理でこれがエラーを招くことがある。

そんな時は行ラベルを割り振り直すことで対処できる。

reset_index()を使う。

df = df.reset_index(drop=True)

ちゃんと返り値を保持することを忘れずに。

2つの文字列配列の要素同士を連結する(文字列配列の足し算)

numpyでは配列(行列)の計算が簡単にできる。これは要素が数字の場合だけでなく、ありがたいことに文字列の場合にも使える。文字列の場合にできる計算は足し算(文字列の連結)だけで、使うこともあまりないけど地味にありがたい。

import numpy as np

array1 = np.array([['a', 'b', 'c'],['a', 'b', 'c']], dtype=object)
array2 = np.array([['1', '2', '3'],['1', '2', '3']], dtype=object)
print(array1 + array2)
出力: array([['a1', 'b2', 'c3'],
['a1', 'b2', 'c3']], dtype=object)

 

 

だだし、配列の型の設定をしないとエラーになるので注意。下のように引数の dtype=object を除くとエラーになる。

array1 = np.array([['a', 'b', 'c'],['a', 'b', 'c']])
array2 = np.array([['1', '2', '3'],['1', '2', '3']])
print(array1 + array2)

出力: TypeError: ufunc 'add' did not contain a loop with signature matching types dtype('<U1') dtype('<U1') dtype('<U1')

 

 

もちろん後から型を変換しても大丈夫。

array1 = np.array([['a', 'b', 'c'],['a', 'b', 'c']])
array2 = np.array([['1', '2', '3'],['1', '2', '3']])
print(array1.astype(object) + array2.astype(object))
出力: array([['a1', 'b2', 'c3'],
['a1', 'b2', 'c3']], dtype=object)

  

 

 

 

 

DataFrameからリストやnumpy.ndarrayへの変換

DataFrameからnumpy.ndarrayへの変換

.valuesと付け足すだけ。pandas.Seriesの場合も同様の処理で変換が可能。

import numpy  as np
import pandas as pd

dataframe = pd.DataFrame([[1, 2, 3], [4, 5, 6]], dtype=int)
array1    = dataframe.values.tolist()
print(array1, type(array1))

series = pd.Series([11, 12, 13], dtype=int)
array2 = series.values.tolist()
print(array2, type(array2))

 

DataFrameからリストへの変換

.valuesで一度numpy.ndarrayにしたのち、numpy.tolist()を使う。

list1 = dataframe.values.tolist()
print(list1, type(list1))

list2 = series.values.tolist()
print(list2, type(list2))

 

ndarrayからDataFrameへの変換

念のため逆も書いておく。

df_new     = pd.DataFrame(array1)
series_new = pd.Series(array2)

 

リストからDataFrameへの変換
df_new     = pd.DataFrame(list1)
series_new = pd.Series(list2)

 

 

 

pandasでcsvファイルを読み込む際にあえてカラム(列)を分けない

ファイルの読み込みはいくつか方法があることは前回の記事に書いた。

spcx8.hatenablog.com

 

読み込んだ後の処理を考えると、numpyやpandasで読みたい。でも中身が文字列を含む場合、numpyは使えないのでpandasで読むことになる。

困るのは読み込む対象のファイルの形式が整っていない場合。列数が揃っていない、特に先頭行の列数が少ない場合に読み込みエラーが起こる。

そんな場合は、あえて列を分けずにn行1列のデータフレームとして読み込む方法もある。以下のように引数の delimiter で改行コード'¥n'を指定すればOK。

import pandas as pd

df = pd.read_csv('data.txt', skiprows=0, header=None, delimiter='¥n', index_col=None)

列の分割はデータを読み込んだ後に必要な箇所だけ行う。DataFrameからリストやnumpy.ndarrayへの変換はいくつかの方法がある。それはまた別の機会に。

 

 

 

 

 

csvファイルやexcelファイル(xls, xlsx)を読み込む

 csvファイルやexcelファイル(xls, xlsx)を読み込む場合のコードはいくつかあるのでまとめておく。

 

(1) 標準ライブラリのcsvを使う

import csv

with open('data.txt', 'r', encoding='utf-8') as f:
dataReader = csv.reader(f, lineterminator='\n')
for row in dataReader:
    print(row)

第二引数を'rb'とすればバイナリファイルが扱える。
追加のライブラリが不要。.txt / .csvのどちらも読み込み可能。
空白や文字列があってもOK。

ただし、中身を取り出すのにfor構文が必要で不便。

 

(2) numpy を使う

import numpy as np

data = np.loadtxt('data.txt', delimiter=',', skiprows=0)

np.ndarray型で読み込む。.txt / .csvのどちらも読み込み可能。
ただし,空白や文字列があるとエラーになる。
大抵は先頭行が項目名になってい流けど、その場合は引数をskiprows=1として1行スキップすればOK。

またはgenfromtxt()を使う。空白や文字列があるとnanにしてくれる。

data = np.genfromtxt('data.txt', delimiter=',')

 

 (3) pandasを使う

import pandas as pd

df = pd.read_csv('data.txt', skiprows=0, header=0, index_col=0)

pandas.Dataframe型で読み込む。.txt / .csvのどちらも読み込み可能。
空白や文字列があってもOK。

引数がたくさんあって色々調整できる

header : 項目名に使う行を指定。Noneとしておくと項目名がなくなり、先頭行からデータとして読み込む

index_col:行名として使う列を指定。

その他の引数は省略。 下は関連記事へのリンク。

spcx8.hatenablog.com

 

 

excelファイル(xls, xlsx)を読み込みたい場合は、read_excel()を使う。

df = pd.read_excel('data.xls', skiprows=0, header=0, index_col=2)

 詳しくは別記事で。

 

 

 

 

配列内の各要素に含まれる特定の文字列を置換・削除する方法

文字列の置換はreplace()を使う。

string = 'abcde'
string_new = string.replace('a', 'A')
print(string_new)

出力: 'Abcde'

 

これが使えるのは単独の文字列だけで、配列(各要素が文字列になっている配列)には使えない。

str_list = ['abcde','abcde']
str_list_new = str_list.replace('a', 'A')

これを処理しようとするとエラーになる。
AttributeError
: 'list' object has no attribute 'replace'

 

なので以下のように、配列を一旦単独の文字列に変換し、replace()で置換、のちに配列に戻すという処理をする。

str_list = ['abcde','abcde']
string = ",".join(str_list)
string_new = string.replace('a', 'A')
str_list_new =  string_new.split(",")
print(string_new)

出力: ['Abcde', 'Abcde']

 

ちなみに、このreplace()の2番目の引数を空白('')にしておけば、削除の処理ができる。

string_new = string.replace('a', '')

 

 

 WEB/EC専門の転職支援サービス【サポタント】

 

 

配列から要素をランダムに抽出するための「インデックス」を作る

配列から要素をランダムに抽出するには、(要素の抽出に使う)インデックスをランダムにしておくだけでいい。

random_array = array[random_index]

ここではrandom_indexも配列。

 

以下は関連記事。

spcx8.hatenablog.com

 

順序をランダムにしたインデックス(配列)の作り方は色々ある。比較のため処理時間を測定。いずれも0~99,999の数字を重複なしでランダムに並べた配列を生成している。

import numpy as np

idx = np.array(range(100000))
np.random.shuffle(idx)

 → 所要時間:17 msec

 

idx = np.arange(0, 100000, 1)
np.random.shuffle(idx)

 → 所要時間:2.6 msec

 

idx = np.random.choice(100000, 100000,replace=False)

 → 所要時間:2.0 msec

 

idx = np.random.randint(0,100000,100000)  

 → 所要時間:2.0 msec

 

np.random.randint() とnp.random.choice() が一位タイ。中身の処理は一緒なんだろうか。こうしてみるとnp.random.shuffle()も大して変わらない。

かと言って抽出するもとの配列そのものをランダムにシャッフルしようとすると、その配列のサイズが大きい場合は処理が重くなるのでやらない方がいい。

 

 

 WEB/EC専門の転職支援サービス【サポタント】