ディレクトリ構造を持つjsonファイルたちを形態素解析をしてcsvに一括変換

複雑なディレクトリ構造を持つjsonファイルをcsvに一括変換したい


日付毎に記録されたjsonデータをcsvに変換したいとする。

ここでまず以下の方法が考えられる1. json⇒csvに変換してくれるサイトを利用2. pythonの変換ライブラリ(pd.read_json()など)を使用する

しかしながら、このどちらも以下の問題を抱えていた
1...一度に変換できる容量に制限アリ&同様のディレクトリを手作業で作り直すのが面倒
2...pd.json_read()でエンコーディングエラー多発

そのため、今回はjson⇒numpy⇒csvとワンクッション置いて必要な情報のみを取り出した

1. 重for文をさけて2018-01-02.jsonのようなファイルパスを表現する

まずこのように内包表記を定義します

#内包表記で重複for分を避ける
   years = range(2018,2019)
   months = range(1, 13)
   days = range(1,32)
   combinations = [(year, month, day)
                   for year in years
                   for month in months
                   for day in days]

この内包表記を利用することで、for文は一度で表現することができます`

   for year, month, day in combinations:
       #ファイル名に合うようにゼロ埋めを実行. ex)2018-09-01
       date = str(year) + '-' + str(month).zfill(2) + '-' + str(day).zfill(2)
       #pathの生成を自動化(ディレクトリ名もそのうち自動で)
       path = "C:/Users/名前/Desktop/json/目的のディレクトリ/" + str(date) + ".json"


2.ファイルパスの判定とjson⇒numpy

1でjsonファイルのpathを自動生成することが出来ました。しかしながら、生成した日付のjsonファイルがない場合エラーを吐いてしまいます。
そこで、os.path.isfile(path)という関数を使用することでpathの存在を判定し、同時にjson⇒numpyへ変換してしまいましょう


if(os.path.isfile(path)):
           #日付代わりにカウンターを更新。これが行の値になる
           count += 1
           #以下、encodingを指定しないとエラーを吐く
           f = None
           f = open(path, 'r', encoding="utf-8")
           #ファイルのデータを取得
           json_data = json.load(f)
           #numpyにぶち込む
           data_ = []
           data_ = np.array(json_data)

elseは今回特に指定しませんでした。

3.データのクリーニング(今回は自然言語処理用)と単語抽出


今回使用するjsonファイルの特徴を見てクリーニング方法を検討します
テキストを含むjsonファイルはすべて
{'type': 'message'
から始まっていたので、こちらを判定に利用しました

#data_をクリーニングしてから全体の配列に格納
           for i in range(len(data_)):
               data_text = str(data_[i])
               text_ = data_text.split(',')
               #メッセージだけを取り出す
               if(text_[0]=="{'type': 'message'"):
                   rm = "'text': "
                   pure_text = clean_text(text_[2].replace(rm,''))
                   print(pure_text)
                   tokens = t.tokenize(pure_text)
                   for token in tokens:
                       partOfSpeech = token.part_of_speech.split(',')[0]
                       # 今回抽出するのは名詞だけ。(もちろん他の品詞を追加、変更、除外可能。)
                       if partOfSpeech == u'名詞':
                           each_data.append(token.surface) # token.surfaceは表層形(語彙)。詳しくはこちら...http://ailaby.com/janome/
                   #抽出した名詞たちをdata_allに追加していく。
                   data_all.append(each_data)
                   each_data = []

 4. 形態要素解析後のデータをexcelファイルに出力

   ## 文章を形態素毎に分割したデータをいれるエクセルファイル作成(今回は名詞のみ)
   # 例)C:\Users\〜\Documents\〜
   # パスの前のrは省略しない
   data_book = xlsxwriter.Workbook("例)C:\Users\〜\Documents\ファイル名1.xlsx")
   # シート作成・変数定義
   data_sheet = data_book.add_worksheet('data')
   for row in range(len(data_all)):
       for i in range(len(data_all[row])):
           data_sheet.write(row, i, data_all[row][i])
   # エクセルを保存
   data_book.close()

5. 名詞の頻度ランキングをexcelファイルに出力

   #すべての語彙を同じ配列に格納
   chain_data = list(chain.from_iterable(data_all))
   c = Counter(chain_data)
   result_ranking = c.most_common(1000) # 出現頻度100位までを変数に格納
   # 語彙出現ランキングを記述するエクセルを作成(パスはファイルを作成したいところに)
   result_book = xlsxwriter.Workbook("例)C:\Users\〜\Documents\ファイル名2.xlsx")
   # resultという名前のシートを作成
   result_sheet = result_book.add_worksheet('result')
   for row in range(len(result_ranking)):
       for i in range(len(result_ranking[row])):
           result_sheet.write(row, i, result_ranking[row][i])
   # エクセルを保存
   result_book.close()

6.おつかれさまでした


これで大体のjsonファイルをcsvで取り扱えそうですね


コード全文


#python:analysis.py
import pandas as pd
import json
import os
import os.path
import numpy as np
from janome.tokenizer import Tokenizer
import xlrd
import xlsxwriter
from collections import Counter
from itertools import chain
#テキストデータをクリーニングする関数
def clean_text(replaced_text):
   """
   \S+ matches all non-whitespace characters (the end of the url)
   :param html_text:
   :return:
   """
   replaced_text = re.sub(r'http\S+', '', replaced_text)
   replaced_text = re.sub(r'[@@]\w+', '', replaced_text)  # メンションの除去
   replaced_text = re.sub(r' ', ' ', replaced_text)  # 全角空白の除去
   replaced_text = re.sub(r'<', ' ', replaced_text)  # 全角空白の除去
   replaced_text = re.sub(r'>', ' ', replaced_text)  # 全角空白の除去
   return replaced_text
########################################################
#メイン処理
if __name__ == "__main__":
   #内包表記で重複for分を避ける
   years = range(2018,2019)
   months = range(1, 13)
   days = range(1,32)
   combinations = [(year, month, day)
                   for year in years
                   for month in months
                   for day in days]
   #内包表記で繰り返し処理
   #縦軸の日付をうまく行列に反映できないので、とりあえずカウンターを設置する
   count = 0
   data_all = [] #テキストファイルのまとめ先
   each_data = [] #語彙の格納先
   t = Tokenizer() #形態素解析用のモジュール
   #1.形態素解析
   for year, month, day in combinations:
       #ファイル名に合うようにゼロ埋めを実行. ex)2018-09-01
       date = str(year) + '-' + str(month).zfill(2) + '-' + str(day).zfill(2)
       #pathの生成も自動化(channelもそのうち自動で)適宜読み替えてpathを設定してください
       path = "C:/Users/ユーザー名/Desktop/json/目標のディレクトリ/" + str(date) + ".json"
       if(os.path.isfile(path)):
           #日付代わりにカウンターを更新。これが行の値になる
           count += 1
           #encodingを指定しないとエラーを吐く
           f = None
           f = open(path, 'r', encoding="utf-8")
           #print(f)
           #ファイルのデータを取得
           json_data = json.load(f)
           #numpyにぶち込む
           
           data_ = []
           data_ = np.array(json_data)
           
           #count行目に入る値
           print(count)
           #data_をクリーニングしてから全体の配列に格納
           for i in range(len(data_)):
               #print(data_[i])
               data_text = str(data_[i])
               #print(data_text)
               text_ = data_text.split(',')
               #メッセージだけを取り出す
               if(text_[0]=="{'type': 'message'"):
                   rm = "'text': "
                   pure_text = clean_text(text_[2].replace(rm,''))
                   print(pure_text)
                   tokens = t.tokenize(pure_text)
                   for token in tokens:
                       partOfSpeech = token.part_of_speech.split(',')[0]
                       # 今回抽出するのは名詞だけ。(もちろん他の品詞を追加、変更、除外可能。)
                       if partOfSpeech == u'名詞':
                           each_data.append(token.surface) # token.surfaceは表層形(語彙)。詳しくはこちら...http://ailaby.com/janome/
                   #抽出した名詞たちをdata_allに追加していく。
                   data_all.append(each_data)
                   each_data = []
   ###########################################################
   ## 文章を形態素毎に分割したデータをいれるエクセルファイル作成(今回は名詞のみ)
   # 例)C:\Users\〜\Documents\〜
   # パスの前のrは省略しない
   data_book = xlsxwriter.Workbook("例)C:\Users\〜\Documents\ファイル名1.xlsx")
   # シート作成・変数定義
   data_sheet = data_book.add_worksheet('data')
   for row in range(len(data_all)):
       for i in range(len(data_all[row])):
           data_sheet.write(row, i, data_all[row][i])
   # エクセルを保存
   data_book.close()
   ############################################################
   #すべての語彙を同じ配列に格納
   chain_data = list(chain.from_iterable(data_all))
   c = Counter(chain_data)
   result_ranking = c.most_common(1000) # 出現頻度100位までを変数に格納
   # 語彙出現ランキングを記述するエクセルを作成(パスはファイルを作成したいところに)
   result_book = xlsxwriter.Workbook("例)C:\Users\〜\Documents\ファイル名2.xlsx")
   # resultという名前のシートを作成
   result_sheet = result_book.add_worksheet('result')
   for row in range(len(result_ranking)):
       for i in range(len(result_ranking[row])):
           result_sheet.write(row, i, result_ranking[row][i])
   # エクセルを保存
   result_book.close()

この記事が気に入ったらサポートをしてみませんか?