著者:飯尾 淳
本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温かく見守ってください。皆さんと共に勉強していきましょう。第27回では、異文化間交流教育プロジェクトで得られたオンライン交流データを分析する、筆者の研究例を紹介します。
シェルスクリプトマガジン Vol.97は以下のリンク先でご購入できます。
図2 必要なライブラリをインポートするコード
1 2 3 4 5 6 7 8 |
import pandas as pd import numpy as np import matplotlib.pyplot as plt import japanize_matplotlib import re, os, math from graphviz import Graph from IPython.display import Image, display, display_png from sklearn.linear_model import LinearRegression |
図4 mk_relations()関数を定義するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
def mk_relations(df): # 関係性を抽出する prev = [] relations = {} f = df.columns for i, row in df.iterrows(): # 発言文字数が「0」ではない発言者を抽出 d = dict(zip(f, list(row))) speakers = list(filter(lambda k: d[k] != 0, d.keys())) # 前行のスピーカーと今の行のスピーカーの関係を抽出 # どちらかもしくは両方が空行のときはスキップ if len(prev)*len(speakers) > 0: for p_speaker in prev: for n_speaker in speakers: r = tuple(sorted([p_speaker, n_speaker])) if r not in relations.keys(): relations[r] = 1 else: relations[r] += 1 prev = speakers return relations |
図5 ファイルからターンテイキングの状況を抽出するコード
1 2 3 4 |
filename = 'data/file00.xlsx' df = pd.read_excel(filename).drop(['Unnamed: 0'], axis=1) d = mk_relations(df) d |
図7 conv_dict()関数を定義するコード
1 2 3 |
def conv_dict(d): v = d.values() return dict(zip(d.keys(), map(lambda x: x/max(v), v))) |
図9 count_talk()関数を定義するコード
1 2 3 4 5 |
def count_talk(df): retvar = {} for (name, col) in df.T.iterrows(): retvar[name] = len(list(filter(lambda x: x > 0, col))) return retvar |
図11 render_graph()関数を定義するコード
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 |
def render_graph(filename): print(f'[source] {filename}') (basename, extention) = re.match(r'(.*)\.(.*)', filename).groups() pathname = 'data/'+filename outputfile = f'graphs/{basename}' # データフレームの準備 df = pd.read_excel(pathname).drop(['Unnamed: 0'], axis=1) names = df.columns # 発言の関係性と発言回数の抽出 relations = conv_dict(mk_relations(df)) talk_counts = count_talk(df) talks = conv_dict(talk_counts) # グラフ描画に関する定数など ARROW_WIDTH = 3 colors = ['white', 'azure', 'lavender', 'slateblue', 'navy'] textcolors = ['black', 'black', 'black', 'white', 'white'] # dot属性の準備 dot = Graph(format='png') dot.attr('node', shape='ellipse') dot.attr('node', fontname='Arial') # ノードの追加 for n in talks.keys(): idx = int(talks[n]*(len(colors)-1)) dot.node(n, f'{n} ({talks[n]:4.2f})', style='filled', fillcolor=colors[idx], fontcolor=textcolors[idx]) # エッジの追加 for e in relations.keys(): (src, dst) = e dot.edge(src, dst, penwidth=f'{relations[e]*ARROW_WIDTH:5.3f}') # サマリー表の作成 df_summary = pd.DataFrame({'ID': talk_counts.keys(), '発言回数': talk_counts.values()}) # レンダリング display(df_summary) dot.render(outputfile) display_png(Image(f’graphs/{basename}.png')) |
図15 calc_num_cv()関数を定義するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
def calc_num_cv(filename): print(f'[source] {filename}') (basename, extention) = re.match(r'(.*)\.(.*)', filename).groups() pathname = 'data/'+filename # データフレームの準備 df = pd.read_excel(pathname).drop(['Unnamed: 0'], axis=1) names = df.columns num = len(names) # 発言回数の抽出 talk_counts = count_talk(df) # サマリー表の作成 df_summary = pd.DataFrame({'ID': talk_counts.keys(), '発話回数': talk_counts.values()}) # 平均・標準偏差・変動係数の計算 mu = sum(df_summary['発話回数'])/num # 平均値 sd = math.sqrt(sum((df_summary['発話回数'] - mu) * (df_summary['発話回数'] - mu))/(num-1)) # 不偏標準偏差 print(f'参加者数 = {num}') print(f'平均 = {mu:4.2f}') print(f'不偏標準偏差 = {sd:4.2f}') print(f'変動係数 = {(sd/mu):6.4f}') return num, sd/mu |
図16 すべてのデータから参加者数と変動係数を計算するコード
1 2 3 4 5 6 7 |
files = sorted(os.listdir('data')) table = [] Xlabel = '参加者数' Ylabel = '変動係数' for filename in files: num, cv = calc_num_cv(filename) table.append({ 'Name': filename, Xlabel: num, Ylabel: cv }) |