こんにんちは。那須野です。
Pythonでデータ処理をするにあたって、Pythonならではの自由度の高さや他言語との微妙な差異が気になっていたので、自分がよく書く基本的な処理をまとめてみました。振り返ってみると、numpyとかmatlibとかは入っていないのでPythonの基本って何だろうと思いつつもpandas, json, datetime, gzipなどは入れたので、誰かの参考になれば幸いです。
ちなみに昔、2年前くらいに書いていた記事はこちらです。ご興味ある方は合わせてご査収ください。
【Pythonデータ活用】CSVファイルをJSONファイル、XMLファイルに変換して出力してみる
【備忘録】Pythonでpandasを使ってExcelファイルを読み込んでcsvファイルを出力するまで【Windows PC】
では長い長い本編です。どうぞ。
一番の留意点は、『++』や『--』といったインクリメントがないこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#足し算 print(11 + 5) #出力:16 #引き算 print(11 - 5) #出力:6 #掛け算 print(11 * 5) #出力:55 #割り算 print(11 / 5) #出力:2.2 ※float型で返される #割り算の商 print(11 // 5) #出力:2 ※int型で返される #割り算の余り print(11 % 5) #出力:1 ※int型で返される #累乗 print(11 ** 5) #出力:161051 #インクリメント ※Pythonに『++』は無い a = 1 a += 1 print(a) #出力:2 |
一番の留意点は、やはりmath.round。他言語と違って四捨五入ではなく銀行丸めを採用しているため、厳密に四捨五入をするにはDecimalモジュールを使わないといけない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import math from decimal import Decimal, ROUND_HALF_UP, ROUND_CEILING, ROUND_FLOOR #整数に切り捨て print(math.floor(1.55)) #出力:1 #整数に切り捨て print(int(1.55)) #出力:1 #整数に切り上げ print(math.ceil(1.55)) #出力:2 #整数に四捨五入 print(Decimal(str(1.55)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) #出力:2 #なおroundは最も近い偶数に丸めるため、四捨五入ではない。 #なおfloat型→decimal型からのキャスト時の誤差を防ぐため、有桁小数を処理する場合は文字列化したあとでdecimalにかける。 #小数第一位で切り上げ print(Decimal(str(1.55)).quantize(Decimal('0.1'), rounding=ROUND_CEILING)) #出力:1.6 #小数第一位で切り下げ print(Decimal(str(1.55)).quantize(Decimal('0.1'), rounding=ROUND_FLOOR)) #出力:1.5 #小数第一位で四捨五入 print(Decimal(str(1.55)).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP)) #出力:1.6 |
JavaScriptやPHPに慣れていると文字列や数字などの型を意識せずに結合してしまいがちだが、Pythonでは純粋に文字列同士で結合しないとエラーが起こる。文字列と数字を結合するはstrで文字列型にキャストする必要がある点は留意のこと。一方の便利な点として、スライスで非常に気軽に文字列を抽出できる点が挙げられる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
import re #文字列の結合 print('a' + 'b') #出力:ab #文字列と数字の結合 ※strで文字列化が必須 print('a' + str(1)) #出力:a1 #スライスにて、最初の文字だけを抽出 print('abcde'[0]) #出力:a #スライスにて、2文字目だけを抽出 print('abcde'[1]) #出力:b #スライスにて、最後の文字だけを抽出 print('abcde'[-1]) #出力:e #スライスにて、2文字目以降を抽出 print('abcde'[1:]) #出力:bcde #スライスにて、最後から2文字目までを抽出 print('abcde'[:-1]) #出力:abcd #スライスにて、2~3文字目の抽出 print('abcde'[1:3]) #出力:bc #配列の文字列結合 ※セパレータのメソッドなので注意 print('_'.join(['date','category','name'])) #出力:date_category_name #特定文字列で配列に分割 print('date_category_name'.split('_')) #出力:['date','category','name'] #特定文字列で分割したうえで特定箇所の抽出 print('date_category_name'.split('_')[1]) #出力:category #文字列型の数字を整数型にキャストする print(int('10')) #出力:10 #文字列型の数字を小数型にキャストする print(float('10.5')) #出力:10.5 #置換フィールドによる整形 print('Hello {}!'.format('Tom')) #出力:Hello Tom! #置換フィールドによる整形(複数) print('This {} is {}!'.format('apple', '$3')) #出力:This apple is $3! #置換フィールドによる整形(変数名を明示) print('This {product} is {price}!'.format(product='apple', price='$3')) #出力:This apple is $3! #単純な置換 buf = '2021-04-05' print(buf.replace('-','/')) #出力:2021/04/05 #正規表現のキャプチャグループによる置換 buf = '20210405' print(re.sub(r'(\d{4})(\d{2})(\d{2})', r'\1/\2/\3', buf)) #出力:2021/04/05 |
一番の留意点は、日を扱うdt.dateと日時を扱うdt.datetimeに定義の段階で分かれることだろう。メソッドはほぼ共通であるがゆえに、入口にて明確に意識する点は気を付けたい。それ以外でいうと、足し算引き算をするにはrelativedeltaという別モジュールを使う点が直感的な処理ではないため覚えておきたい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
import datetime as dt from dateutil.relativedelta import relativedelta #※類似するdt.timedeltaではmonths以上が動かない模様。 #日付文字列のdatetime型へのパース buf = '2021/03/14 12:15:03' date = dt.datetime.strptime(buf,'%Y/%m/%d %H:%M:%S') print(date) #出力:2021-03-14 12:15:03 #翌日に変換 date = date + relativedelta(days=1) print(date) #出力:2021-03-15 12:15:03 #文字列として日付だけフォーマットする buf = dt.datetime.strftime(date,'%Y/%m/%d') print(buf) #出力:2021/03/15 #1時間後に変換 date = date + relativedelta(hours=1) print(date) #出力:2021-03-15 13:15:03 #30分後に変換 date = date + relativedelta(minutes=30) print(date) #出力:2021-03-15 13:45:03 #10分後に変換 date = date + relativedelta(seconds=10) print(date) #出力:2021-03-15 13:45:13 #1ヶ月後に変換 date = date + relativedelta(months=1) print(date) #出力:2021-04-15 13:45:13 #1年後に変換 date = date + relativedelta(years=1) print(date) #出力:2022-04-15 13:45:13 #当月初日に変換 date = date.replace(day=1,hour=0,minute=0,second=0) print(date) #出力:2022-04-01 00:00:00 #当月末日に変換 date = date.replace(day=1,hour=0,minute=0,second=0) date = date + relativedelta(months=1,days=-1) print(date) #出力:2022-04-30 00:00:00 #当日以降の月曜日に変換 w = date.weekday() increment = 0 if w == 0 else 7 - w date = date + relativedelta(days=increment) print(date) #当日以前の水曜日に変換 w = date.weekday() decrement = 5 + w if w < 1 else w - 2 date = date + relativedelta(days=-decrement) print(date) |
文字列と同じようにスライスが圧倒的に便利。それ以外では、lambda関数を配列の各要素に一括でかけるmap処理が便利なので、mapの戻り値がオブジェクト(イテレータ)なのでそのままforループはできるが配列として扱いたいときは改めてlistにかける必要がある点と一緒に頭に入れておきたい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
#特定の値を指定数だけ要素に持つ配列を生成する itemList = ['a'] *5 print(itemList) #出力:['a', 'a', 'a', 'a', 'a'] #配列要素を末尾に追加 itemList = ['a','b','c','d','e'] itemList.append('f') print(itemList) #出力:['a','b','c','d','e','f'] #配列と配列を結合 itemList = ['a','b','c','d','e'] itemList.extend(['f','g','h']) print(itemList) #出力:['a','b','c','d','e','f','g','h'] #スライスで配列の頭を削除 itemList = ['a','b','c','d','e'] del itemList[0] print(itemList) #出力:['b',c','d','e'] #スライスで配列の末尾を削除 itemList = ['a','b','c','d','e'] del itemList[-1] print(itemList) #出力:['a',b','c',d'] #スライスで配列の指定箇所を削除 itemList = ['a','b','c','d','e'] del itemList[1:3] print(itemList) #出力:['a','d',e'] #配列の指定値を削除 itemList = ['a','b','c','d','e'] itemList.remove('b') print(itemList) #出力:['a','c',d','e'] #無名関数(lambda)で配列の値を一括変換 itemList = ['a','b','c','d','e'] newitemList = list(map(lambda x : x + '+', itemList)) print(newitemList) #出力:['a+', 'b+', 'c+', 'd+', 'e+'] #関数を定義したうえで配列の値を一括変換 itemList = ['a','b','c','d','e'] def convert(item): return item + '+' newitemList = list(map(convert, itemList)) print(newitemList) #出力:['a+', 'b+', 'c+', 'd+', 'e+'] #配列の中で条件に合致するものを数える itemList = ['a','b','c','d','e'] aCount = sum(item == 'a' for item in itemList) print(aCount) #出力:1 #配列の中で条件に合致するものを抽出する logList = [ {'id':'id1','category':'category1'}, {'id':'id2','category':'category2'}, {'id':'id3','category':'category1'} ] logList = list(filter(lambda x : x['category'] == 'category2', logList)) print(logList) #出力:[{'id':'id2','category':'category2'}] #配列を並び替え(配列のsortメソッド版) logList = [ {'id':'id1','category':'category1'}, {'id':'id2','category':'category2'}, {'id':'id3','category':'category1'} ] logList.sort(key=lambda x : x['id'], reverse=True) print(logList) #出力:[{'id': 'id3', 'category': 'category1'}, {'id': 'id2', 'category': 'category2'}, {'id': 'id1', 'category': 'category1'}] #配列を複数キーで並び替え(配列のsortメソッド版) logList = [ {'id':'id1','category':'category1'}, {'id':'id2','category':'category2'}, {'id':'id3','category':'category1'} ] logList.sort(key=lambda x : (x['category'], x['id']), reverse=True) print(logList) #出力:[{'id': 'id2', 'category': 'category2'}, {'id': 'id3', 'category': 'category1'}, {'id': 'id1', 'category': 'category1'}] #配列を並び替え(組み込み関数のsorted版) logList = [ {'id':'id1','category':'category1'}, {'id':'id2','category':'category2'}, {'id':'id3','category':'category1'} ] logList = sorted(logList, key=lambda x : x['id'], reverse=True) print(logList) #出力:[{'id': 'id3', 'category': 'category1'}, {'id': 'id2', 'category': 'category2'}, {'id': 'id1', 'category': 'category1'}] |
『else if』の書き方が『elif』という非常に独特な書き方なので注意。三項演算子も『{True時の値} if {条件} else {False時の値}』となっていて、口語的な並びで自然言語として読み取りやすいものの他言語と比べると独特なので注意したい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#基本的なifによる分岐 def reply(buf): if len(buf) > 4: print('4文字を超えます') elif len(buf) == 4: print('4文字ちょうどです') else: print('4文字未満です') reply('test') #出力:4文字ちょうどです reply('testA') #出力:4文字を超えます reply('tes') #出力:4文字未満です #三項演算子でifを1行で書く input = 3 result = 1 if input == 1 else 0 print(result) #出力:0 |
Pythonはboolean判定がサポートされていて便利な印象。inによる包含判定がある点、数字の大小関係が3個以上でも直観的に併記できる点はとくに便利。なお非常に違和感がある点としては、多言語でNULLなどと呼ばれる『未定義』の状態が『None』と別文字で表記する必要がある点が挙げられる。JSON形式でファイル出力したりするとnullに変換されるるので非常にややこしい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
#数字の大小関係(2個) print(1 < 2) #出力:True print(1 > 2) #出力:False #※もちろん大なりイコールの場合は『>=』、小なりイコールの場合は『<=』、ノットイコールの場合は『!=』である #数字の大小関係(3個以上) print(1 < 2 < 4) #出力:True print(1 < 2 < 0) #出力:False #※3個以上の大小関係を直観的に併記できるのはPythonの特長。 #特定文字を含むかどうかの判定 print('e' in 'test') #出力:True #※inの後の変数がNULLの場合はエラーになるので注意。 #特定文字から始まるかどうかの判定 print('test'.startswith('t')) #出力:True #特定文字で終わるかどうかの判定 print('test'.endswith('t')) #出力:True #NULLかどうかの判定 temp = None print(temp is None) #出力:True #NULLではないかどうかの判定 temp = None print(temp is not None) #出力:False #配列が特定要素を含むかどうかの判定 valueList = ['apple','banana','orange'] print('apple' in valueList) #出力:True print('strawberry' in valueList) #出力:False #連想配列に特定キーが存在するかどうかの判定 obj = {'id':'id1','date':'2021-03-15','subject':'subjectA','value':10} print('date' in obj) #出力:True print('datetime' in obj) #出力:False print(obj.get('date') is not None) #出力:True print(obj.get('datetime') is not None) #出力:False #※直接obj['datetime']のように参照すると、キーが存在しない場合にエラーになるので注意。 #複数条件が全てTrueであるかどうかのAND判定 buf = 'test' print('e' in buf and buf.startswith('t')) #出力:True print('e' in buf and buf.startswith('s')) #出力:False #複数条件いずれかがTrueであるかどうかのOR判定 buf = 'test' print('e' in buf or buf.startswith('t')) #出力:True print('e' in buf or buf.startswith('s')) #出力:True |
他言語でよくあるインクリメントによるfor ループが存在しないため、インクリメントを意識したループを書くときにはenumerateを使ったりrangeを使ったりインクリメントを明示したwhileを使ったりなど工夫する必要がある。なお、そのデメリットが気にならないほどに、要素そのものをループ変数に参照渡しするforループは非常に便利なので、この特性を有効活用できる書き方に寄せるというのが正攻法だと感じる。
ただし、ループ変数に直接代入をすると「新たに変数が定義されて元変数は更新されない」という罠はPythonでも健在なので、ループ変数を更新する前提の書き方は特に注意する必要がある。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
#================================ # 基本 #================================ #配列のループ itemList = ['a','b','c','d','e'] for item in itemList: if item > 'c': print(item) #出力:d #出力:e #配列のループ(インデックス付き) itemList = ['a','b','c','d','e'] for index,item in enumerate(itemList): if item > 'c': print(index) #出力:3 #出力:4 #固定長のループ count = 0 for index in range(3): count += 1 print(count) #出力:3 #whileによるループ count = 0 while True: count += 1 if count > 4: break print(count) #出力:5 #whileの場合はイテレータ変数の変化が明示されないので、 #不規則な反復処理のうえで条件合致したらbreakする場合に推奨 #================================ # 二重配列 #================================ #二重配列のループ table = [ [1,2,3], [4,5,6], [7,8,9] ] count = 0 for row in table: for cell in row: count += cell print(count) #出力:45 #================================ # 辞書(連想配列) #================================ #辞書オブジェクト(dict)のループ textMap = { 'key1':'hello', 'key2':'world' } for key in textMap: print(key) print(textMap[key]) #出力:key1 #出力:hello #出力:key2 #出力:world #================================ # ループ変数更新の考察 #================================ #ループ変数は参照渡しなので、 #添え字越しでの代入は元変数に反映される table = [ [1,2,3], [4,5,6], [7,8,9] ] for row in table: for iColumn,cell in enumerate(row): if cell > 5: row[iColumn] = 0 print(table) #出力:[[1, 2, 3], [4, 5, 0], [0, 0, 0]] #ループ変数は参照渡しだが、 #ループ変数への直接代入はループ変数が再定義されるだけで、元変数には反映されない table = [ [1,2,3], [4,5,6], [7,8,9] ] for row in table: for cell in row: if cell > 5: cell = 0 print(table) #出力:[[1, 2, 3], [4, 5, 6], [7, 8, 9]] |
jsonモジュールを使うと簡単にJSONファイルの入出力ができる。ファイルから文字列を読み込む際は、UTF-8を前提にしたい。
なお、jsonにはdumps/dump、loads/loadという2種類のメソッドがあり、複数形と単数形という違いに見えるが、機能的にはオブジェクトを直接渡すか文字列を渡すかの違いがあり、意外と重要。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import json parentPath = 'C:/Users/Takumi Nasuno/Desktop/' #※フォルダの区切り文字は『\』ではなく『/』なので注意。 inputData = { 'hello':'こんにちは!' } #JSONファイルとして出力(いったん文字列を介する冗長版) filePath = parentPath + 'dic.json' buf = json.dumps(inputData, ensure_ascii=False) with open(filePath,'wt', encoding='UTF-8') as f: f.write(buf) #JSONファイルとして取り込み(いったん文字列を介する冗長版) filePath = parentPath + 'dic.json' with open(filePath,'rt', encoding='UTF-8') as f: buf = f.read() outputData = json.loads(buf) print(outputData) #出力:{'hello': 'こんにちは!'} #JSONファイルとして出力(オブジェクトを直接) filePath = parentPath + 'dic_direct.json' with open(filePath,'wt', encoding='UTF-8') as f: json.dump(inputData, f, ensure_ascii=False) #JSONファイルとして取り込み(オブジェクトを直接) filePath = parentPath + 'dic_direct.json' with open(filePath,'rt', encoding='UTF-8') as f: outputData = json.load(f) print(outputData) #出力:{'hello': 'こんにちは!'} |
pandasを使う場合は、組み込み関数やapplyを中心とした一括変換でパフォーマンスが向上するので、一括変換を意識して活用していきたい。行列のループを書いて個別にループ処理することも無理矢理はできるが、効率では劣る。注意点として、ExcelやCSVなどの外部ファイルを取り込んだときに空白だった箇所は空白(『』)ではなく『NaN』として値が入るため、いわゆるNULL判定をpd.isna関数で行う点は留意したいところ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
import pandas as pd #カラム指定でデータフレームを生成 columns = ['id','date','subject','value'] data = [ ['id1', '2021-03-15', 'subjectA', 10], ['id2', '2021-03-15', 'subjectB', 5], ['id3', '2021-03-16', 'subjectB', 12], ['id4', '2021-03-17', 'subjectC', -5] ] df = pd.DataFrame(data, columns=columns) print(df) #出力: # id date subject #0 id1 2021-03-15 subjectA #1 id2 2021-03-15 subjectB #2 id3 2021-03-16 subjectB #3 id4 2021-03-17 subjectC #特定セルがNULLかどうかの判定 print(pd.isna(df['id'][0])) #出力:False #行のループ sumValue = 0 for iRow, row in df.iterrows(): sumValue += row['value'] print(sumValue) #出力:22 #列のループ buf = '' for iColumn, column in df.iteritems(): buf += str(column[0]) print(buf) #出力:id12021-03-15subjectA10 #行列のループ buf = '' for iRow, row in df.iterrows(): for iColumn, column in df.iteritems(): buf += str(row[iColumn]) print(buf) #出力:id12021-03-15subjectA10id22021-03-15subjectB5id32021-03-16subjectB12id42021-03-17subjectC-5 #セルを参照するときにrowに対してiColumnで取得するのがコツ。 #apply lambdaによる指定列の一括変換 df['subject'] = df['subject'].apply(lambda x : x.replace('subject','表題')) print(df) #出力: # id date subject value #0 id1 2021-03-15 表題A 10 #1 id2 2021-03-15 表題B 5 #2 id3 2021-03-16 表題B 12 #3 id4 2021-03-17 表題C -5 #なお、lambdaを変数に格納することも可 updateSubject = lambda x : x.replace('表題','subject') df['subject'] = df['subject'].apply(updateSubject) print(df) #出力: # id date subject value #0 id1 2021-03-15 subjectA 10 #1 id2 2021-03-15 subjectB 5 #2 id3 2021-03-16 subjectB 12 #3 id4 2021-03-17 subjectC -5 #なお、def関数でも書ける def updateValue(number): return number * 2 df['value'] = df['value'].apply(updateValue) print(df) #出力: # id date subject value #0 id1 2021-03-15 subjectA 20 #1 id2 2021-03-15 subjectB 10 #2 id3 2021-03-16 subjectB 24 #3 id4 2021-03-17 subjectC -10 #特定列の値による行フィルター(indexはそのままとなるので留意) filteredDf = df.query('date > "2021-03-16"') print(filteredDf) #出力: # id date subject value #3 id4 2021-03-17 subjectC -10 |
ファイル処理で気を付けたいものナンバーワンは、とくかくエンコード。UTF-8を前提とした処理にShift_JISという悪しき習慣が紛れて処理が回らないというイージーミスは避けたいし、UTF-8にしてもUnicodeエスケープするのかしないのかは明示的に書きたい。また、実務上はgzip圧縮しての管理がよく出てくるため、圧縮形式としてのgzipの処理も重要。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
import pandas as pd import gzip parentPath = 'C:/Users/Takumi Nasuno/Desktop/' #※フォルダの区切り文字は『\』ではなく『/』なので注意。 #================================ # サンプルデータの生成 #================================ columns = ['列A','列B','列C'] data = [ [1,2,3], [4,5,6], [7,8,9] ] df = pd.DataFrame(data, columns=columns) #================================ # output基本 #================================ #▼CSV編 #df.to_csvのエンコードはUTF-8がデフォルト #デフォルトのUTF-8にてCSV出力 filePath = parentPath + 'output_utf8.csv' df.to_csv(filePath, index=False) #Shift_JISを明示的に指定して、CSV出力 filePath = parentPath + 'output_shiftjis.csv' df.to_csv(filePath, index=False, encoding='Shift_JIS') #▼JSON編 #df.to_jsonのエンコードはOSのシステムロケールに従うので、 #Windowsの場合はシステムロケールにて『ベータ:ワールドワイド言語で Unicode UTF-8 を使用』にチェックを入れるか、 #後述する明示的な処理をしないとShift_JISになっていることが多いので注意。 #JSON出力(各行を要素とした配列) filePath = parentPath + 'output.json' df.to_json(filePath, orient='records', force_ascii=False) #JSONLines形式での出力(各行を独立したJSONとして改行区切りにしたもの) filePath = parentPath + 'output.jsonl' df.to_json(filePath, orient='records', force_ascii=False, lines=True) #UTF-8を明示して、JSON形式での出力 filePath = parentPath + 'output_uft8.json' buf = df.to_json(orient='records', force_ascii=False) with open(filePath,'wt', encoding='UTF-8') as f: f.write(buf) #UTF-8を明示して、JSONLines形式での出力 filePath = parentPath + 'output_uft8.jsonl' buf = df.to_json(orient='records', force_ascii=False, lines=True) with open(filePath,'wt', encoding='UTF-8') as f: f.write(buf) #▼Excel編 #Excelファイルとして出力 filePath = parentPath + 'output.xlsx' df.to_excel(filePath, sheet_name='Sheet1', index=False) #================================ # input基本 #================================ #▼CSV編 #CSVファイル(Shift_JIS)の取り込み filePath = parentPath + 'output_shiftjis.csv' df = pd.read_csv(filePath, encoding='Shift_JIS') #CSVファイル(UTF-8)の取り込み filePath = parentPath + 'output_utf8.csv' df = pd.read_csv(filePath, encoding='UTF-8') #▼JSON編 #JSONファイル(UTF-8)の取り込み filePath = parentPath + 'output_uft8.json' df = pd.read_json(filePath, orient='records', encoding='UTF-8') #JSONLinesファイル(UTF-8)の取り込み filePath = parentPath + 'output_uft8.jsonl' df = pd.read_json(filePath, orient='records', encoding='UTF-8', lines=True) #▼Excel編 #Excelのシート名一覧の取得 filePath = parentPath + 'output.xlsx' sheetNameList = pd.ExcelFile(filePath).sheet_names print(sheetNameList) #出力:['Sheet1'] #Excelシートの取り込み(ヘッダーあり) filePath = parentPath + 'output.xlsx' sheetName = 'Sheet1' df = pd.read_excel(filePath, sheet_name=sheetName) print(df) #出力 # 列A 列B 列C #0 1 2 3 #1 4 5 6 #2 7 8 9 #Excelシートの取り込み(ヘッダーなしで1行目をスキップ) filePath = parentPath + 'output.xlsx' sheetName = 'Sheet1' df = pd.read_excel(filePath, sheet_name=sheetName, header=None, skiprows=1) print(df) #出力 # 0 1 2 #0 1 2 3 #1 4 5 6 #2 7 8 9 #カラム名(ヘッダー)の上書き columns = ['colA', 'colB', 'colC'] df.set_axis(columns, axis='columns', inplace=True) print(df) #出力 # colA colB colC #0 1 2 3 #1 4 5 6 #2 7 8 9 #================================ # 応用のgzip圧縮 #================================ #愚直にgzipモジュールを使って、JSONLinesファイルを保存 filePath = parentPath + 'output.jsonl.gz' buf = df.to_json(orient='records', force_ascii=False, lines=True) with gzip.open(filePath, 'wt', encoding='UTF-8') as f: f.write(buf) #※to_jsonにてファイル名を指定せず、文字列として戻してgzip.open.writeに渡すのがポイント。 #愚直にgzipモジュールを使って、JSONLinesファイルの取り込み filePath = parentPath + 'output.jsonl.gz' with gzip.open(filePath, 'rt', encoding='UTF-8') as f: buf = f.read() df = pd.read_json(buf, orient='records', encoding='UTF-8', lines=True) #df.to_jsonのオプションでcompression='gzip'を指定して、JSONLinesファイルを保存 filePath = parentPath + 'output_direct.jsonl.gz' df.to_json(filePath,orient='records', force_ascii=False, lines=True, compression='gzip') #df.read_jsonのオプションでcompression='gzip'を指定して、JSONLinesファイルの取り込み filePath = parentPath + 'output_direct.jsonl.gz' df = pd.read_json(filePath, orient='records', encoding='UTF-8', lines=True, compression='gzip') |
以上、ざっくりしたまとめでした。プログラミングの世界は日々勉強ですね。
正直なところ、Pythonの特長はモジュール(ライブラリ)の豊富さにあるので、こういった基本的な処理だけであればGoで書いた方がパフォーマンスが大きく向上すると思うとGoで書いた方がいいんじゃないかと思いつつも、マーケット的にPython人材よりもGo人材の方が圧倒的に少ないうえに学習コストも高いことを考えるとビジネス的には非常に難しい判断どころなんだろうなと思う今日この頃です。