著者:飯尾 淳
本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温かく見守ってください。皆さんと共に勉強していきましょう。第27回では、異文化間交流教育プロジェクトで得られたオンライン交流データを分析する、筆者の研究例を紹介します。
シェルスクリプトマガジン Vol.97は以下のリンク先でご購入できます。![]()
![]()
図2 必要なライブラリをインポートするコード
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()関数を定義するコード
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 ファイルからターンテイキングの状況を抽出するコード
filename = 'data/file00.xlsx'
df = pd.read_excel(filename).drop(['Unnamed: 0'], axis=1)
d = mk_relations(df)
d
図7 conv_dict()関数を定義するコード
def conv_dict(d):
v = d.values()
return dict(zip(d.keys(), map(lambda x: x/max(v), v)))
図9 count_talk()関数を定義するコード
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()関数を定義するコード
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()関数を定義するコード
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 すべてのデータから参加者数と変動係数を計算するコード
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 })





