def set_csv_path(self, url): ''' CSVファイルを生成する絶対パスを生成します。 ''' ASIN = URLValidator.get_ASIN_by_pr(url) path = f'csv/reviews/{ASIN}/{ASIN}.csv' self.file_path['review'] = get_abs_path(__file__, path) path = 'csv/log/reviews/log.csv' self.file_path['log'] = get_abs_path(__file__, path)
def set_csv_path(self): ''' CSVを出力するファイルパスをセットします。 ''' if self.mode == 'y': # self.tweets_path = get_abs_path( # __file__, f'csv/users/{self.keyword}/tweets.csv') # self.tweets_text_path = get_abs_path( # __file__, f'csv/users/{self.keyword}/tweets_text.csv') # self.params_path = get_abs_path( # __file__, 'csv/params/user/params.csv') if self.screen_name is None: # ユーザーを指定して取得 (screen_name) self.tweets_path = get_abs_path( __file__, f'csv/users/{self.keyword}/tweets.csv') self.tweets_text_path = get_abs_path( __file__, f'csv/users/{self.keyword}/tweets_text.csv') self.params_path = get_abs_path( __file__, 'csv/params/user/params.csv') else: self.tweets_path = get_abs_path( __file__, f'csv/users/{self.screen_name}/tweets.csv') self.tweets_text_path = get_abs_path( __file__, f'csv/users/{self.screen_name}/tweets_text.csv') self.params_path = get_abs_path( __file__, 'csv/params/user/params.csv') elif self.mode == 'k': # キーワードで取得 self.tweets_path = get_abs_path( __file__, f'csv/keywords/{self.keyword}/tweets.csv') self.tweets_text_path = get_abs_path( __file__, f'csv/keywords/{self.keyword}/tweets_text.csv') self.params_path = get_abs_path( __file__, 'csv/params/keyword/params.csv')
def output_comments_txt(review_path: Path, freq: str = 'M', is_div: bool = False): ''' レビューのコメントを月別にtxt形式で出力します。 ''' # データフレームの読込み df = pd.read_csv(review_path) # 日付のカラムをdatetime形式へ変換 df['dates'] = pd.to_datetime(df['dates']) # 日付のカラムをインデックスへセット df.set_index('dates', inplace=True) # レビューを月別に集計 grouped = df.groupby(pd.Grouper(freq=freq)) if is_div: # 月別に集計したタプルから日付とコメントを取り出し for idx, group in grouped: # 分かち書きしたコメントをリストへ格納 # text_wakati = ginza_de_wakatiko(group['comments'].values) text_wakati = ginza_de_wakatiko( group['comments'].values, True, True) idx = idx.strftime('%Y-%m-%d') # 分かち書きしたテキストを出力するファイルのパスをセット # wakati_path = pm.get_abs_path(review_path, f'wakati/{idx}.txt') wakati_path = pm.get_abs_path( review_path, f'wakati_nva_lemma/{idx}.txt') # 分かち書きしたテキストをファイルへ出力 with open(wakati_path, mode='w', encoding='utf_8') as f: for text in text_wakati: # f.write('\n'.join(text)) f.write(text + '\n') print(f'file name "{idx}" was output. format: .txt') else: # 月別に改行したテキストを単一のファイルに出力する場合 # 分かち書きしたテキストを出力するファイルのパスをセット wakati_path = pm.get_abs_path(review_path, 'wakati/all_wakati.txt') # ファイルを開く with open(wakati_path, mode='w', encoding='utf_8') as f: for idx, group in grouped: # 分かち書きしたコメントをリストへ格納 text_wakati = ginza_de_wakatiko(group['comments'].values) # 分かち書きしたテキストをファイルへ出力 for text in text_wakati: # f.write('\n'.join(text)) f.write(text) else: f.write('\n') print(f'"{idx}" wrote.')
def plot_chronological(ratio: bool): paths = get_all_reviews_paths(is_format=True) for path in paths: df = dfreshaper.aggregate_by_rate(path) r_plotter = ReviewPlotter(headless=True) # r_plotter.plot_stacked_bar_graph(df, ratio=ratio) r_plotter.plot_line_of_rate(df, ratio=ratio) if ratio: path = pm.get_abs_path(path, f'plots/{path.stem[1:]}_line_ratio.png') # path, f'plots/{path.stem[1:]}_chronological_ratio.png') else: path = pm.get_abs_path(path, f'plots/{path.stem[1:]}_line.png') # path, f'plots/{path.stem[1:]}_chronological.png') r_plotter.save(path)
def update_params_by_user(self, params: dict): ''' ユーザー検索パラメータにキーワードをセットします。 ''' if self.params_path is None: # ユーザーを指定して取得 (screen_name) self.params_path = get_abs_path( __file__, 'csv/params/user/params.csv') # キーワード重複時アーリーリターン if self.has_duplicate_screen_name(params): return # 新規データフレームを作成 df_new_params = pd.DataFrame( # DataFrame結合時にdtypeがint型からfloat型への変換を防ぐためnanを-1で置換する [[-1, -1, -1, params['keyword']]], columns=['since_id', 'max_id', 'user_id', 'screen_name']) # パラメータを読み込みます。 if Path(self.params_path).exists(): df_params = pd.read_csv(self.params_path) df_new_params = df_params.append(df_new_params) # CSVを出力します。 df_new_params.to_csv(self.params_path, index=False)
def txt2d2vmodel(ASIN: str): ''' テキストからDoc2Vecモデルを生成 ''' # 絶対パスをセット path = f'csv/reviews/{ASIN}/wakati/wakati.txt' path = pm.get_abs_path(__file__, path) with open(path, mode='r', encoding='utf_8') as f: # 1文書ずつ、単語に分割してリストへ格納[([単語1,単語2,単語3],文書id),...] # words:文書に含まれる単語のリスト(単語の重複あり) # tags:文書の識別子(リストで指定.1つの文書に複数のタグを付与できる) trainings = [ TaggedDocument(words=data.split(), tags=[i]) for i, data in enumerate(f) ] # トレーニング m = Doc2Vec(documents=trainings, dm=1, vectorize=300, window=8, min_count=10, workers=4) # モデルのセーブ m.save("./doc2vec.model")
def generate_csv_from_dict(review: dict, file_path: str, is_latest: bool = False): ''' 辞書からCSVを生成します。 ''' # 辞書からデータフレームを生成 df_new = pd.DataFrame.from_dict(review) # 指定したパスにファイルが存在するか if Path(file_path).exists(): if is_latest: # 新しい場合 # 一時ファイルのパスを生成 tmp_path = get_abs_path(file_path, 'tmp.csv') # 既存CSVを一時ファイルにリネーム os.rename(file_path, tmp_path) # 最新データの新規CSVを生成 df_new.to_csv(file_path, index=False) # 既存のCSVを分割読込 df_chunks = pd.read_csv(tmp_path, chunksize=50) # 分割読込した既存CSVを新規に生成したCSVに追記 for chunk in df_chunks: chunk.to_csv(file_path, mode='a', header=False, index=False) # 一時ファイルを削除する os.remove(tmp_path) else: # 古い場合 # 既存CSVの末尾に追記 df_new.to_csv(file_path, mode='a', header=False, index=False) else: # 存在しない場合 df_new.to_csv(file_path, index=False)
def __init__(self, mode: str = 'k'): # print('インスタンスが生成されました。') # 保存するデータ群 self.list_created_at = [] self.list_id = [] self.list_full_text = [] self.list_user_id = [] self.list_user_screen_name = [] self.list_formatted_text = [] # self.list_user_mentions = [] # self.list_urls = [] self.tweets_path = self.tweets_text_path = self.params_path = None # self.path_by_user = self.path_by_keyword = {} self.keyword = self.screen_name = None self.mode = mode self.params = {} if self.mode == 'y': self.params_path = get_abs_path( __file__, 'csv/params/user/params.csv') elif self.mode == 'k': self.params_path = get_abs_path( __file__, 'csv/params/keyword/params.csv')
def copy_all_reviews(): ''' コピー元ファイルの更新日時が古い場合はコピー先のファイルを上書きをしない。 非推奨:コマンド打ったほうが簡単 ''' # コピー元のレビューディレクトリ # reviews_path_src = r'C:/Users/yaroy/Documents/Python_Projects/Crawler/Amazon/csv/reviews/' reviews_path_src = r'/home/ubuntu/Documents/python_projects/py37/Web_Crawler/Amazon/csv/reviews/' reviews_path_src = pathlib.Path(reviews_path_src) reviews_path_src = str(reviews_path_src) # コピー先のレビューディレクトリ reviews_path_dst = pm.get_abs_path(__file__, 'csv/reviews/') reviews_path_dst = str(reviews_path_dst) # 更新/差分ファイルをコピー dir_util.copy_tree(reviews_path_src, reviews_path_dst, update=1)
def get_all_reviews_paths(is_format: bool = False): ''' Return the generator for all amazon review paths. ''' # レビューファイルのパス reviews_path = pm.get_abs_path(__file__, 'csv/reviews/') # Windowsはパスをエスケープ文字'\'とバックスラッシュ'\'の'\\'でパスを表現している。 pattern = r'[/|\\]+(?![a-z])[A-Z0-9]+\.csv' repatter = re.compile(pattern) if is_format is False: # 辞書内包表記 {key:"拡張子のないファイル名",item:"ファイルのパス"} paths_gen = [ p for p in reviews_path.glob('**/*.csv') if re.search(repatter, str(p)) ] else: # 辞書内包表記 {key:"拡張子のないファイル名",item:"ファイルのパス"} paths_gen = [ p.with_name(f'f{p.name}') for p in reviews_path.glob('**/*.csv') if re.search(repatter, str(p)) ] return paths_gen
import pathlib import transformers from my_module import path_manager as pm import tensorflow as tf import numpy as np import pandas as pd import statistics model_name = str( pm.get_abs_path(__file__, 'resources/BERT/BERT-base_mecab-ipadic-bpe-32k')) tokenizer = transformers.BertTokenizer.from_pretrained(model_name) # テキストのリストをtransformers用の入力データに変換 def to_features(texts, max_length): shape = (len(texts), max_length) # input_idsやattention_mask, token_type_idsの説明はglossaryに記載(cf. https://huggingface.co/transformers/glossary.html) input_ids = np.zeros(shape, dtype="int32") attention_mask = np.zeros(shape, dtype="int32") token_type_ids = np.zeros(shape, dtype="int32") for i, text in enumerate(texts): encoded_dict = tokenizer.encode_plus(text, max_length=max_length, pad_to_max_length=True) input_ids[i] = encoded_dict["input_ids"] attention_mask[i] = encoded_dict["attention_mask"] token_type_ids[i] = encoded_dict["token_type_ids"] return [input_ids, attention_mask, token_type_ids] # 単一テキストをクラス分類するモデルの構築
from torch.utils.data import DataLoader, RandomSampler, SequentialSampler from torch.utils.data import TensorDataset, random_split # Tokenizerの準備 from transformers import BertJapaneseTokenizer from my_module import path_manager as pm import torch import numpy as np import statistics import sys # シードを固定することで学習の再現性を担保する。 torch.manual_seed(0) # 学習済みモデルのロード model_name = str( pm.get_abs_path( __file__, 'resources/BERT/BERT-base_mecab-ipadic-bpe-32k_whole-word-mask')) # Tokenizerのセット tokenizer = BertJapaneseTokenizer.from_pretrained(model_name) # CPU/GPU環境の設定 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") df = pd.read_csv('resources/review/fearphone_review_labeled2.csv') # 文章中の単語数を集計した列を挿入 df['length'] = df['comments'].apply(lambda x: len(tokenizer.tokenize(x))) # 単語数を基準に降順にソート df.sort_values('length', ascending=False, inplace=True) df_neg = df[df['label'] == '__label__0'] df_pos = df[df['label'] == '__label__1'] # データ数の少ない一方の極性にデータ数を揃える。