kukkuのメモ帳

勉強したこと,思ったこと,あったことをつらつら書いていきます

Python初心者がGoogleフォームの結果を集計する

みなさんお久しぶりです。くっくです。

今回はGoogleフォームを集計する話です。 GoogleフォームはGoogleDriveの一種で、アンケートを作れるやつです。アンケート結果はGoogleスプレッドシートで見ることができます。

生成されるスプレッドシートはこんな感じ

タイムスタンプ 性別 好きな食べ物 自転車乗れる?
20XX/0X/XX 00:00:00 男性 りんご YES
20XX/0Y/YY 00:00:00 男性 みかん, オレンジ NO
20XX/0Z/ZZ 00:00:00 女性 バナナ YES

3人ぐらいなら問題ないんですが、これが100人とか200人とかになると、「りんごが好きなのは何人だろう」とか「みかんが好きなら自転車に乗れないかが知りたい」とかのためにいちいち指折り数えるのは非常にしんどいです。 GoogleスプレッドシートExcelで開くことができますが、それでも面倒です。僕はできませんでした。

ならコードでやろう!なにでやろう?Pythonだ!!

と思い立ち、これまで全く使ったことのないPythonで集計することにしました。

目標

  1. 各質問内容に対し回答内容とその数をカウントする。
  2. ある質問が特定の回答の場合のみカウントする。

環境

勉強

Pythonでやろうと思い立ったはいいものの、文法とか全く知りません。こんな時は

dotinstall.com

定番ですね。何かを始めるときは毎回お世話になっています。今まで見たやつを全部メモに残してたのに、すべて消えたのがショックでなりません。

とりあえず、これを全部見て感覚を掴みます。

書いていこう

書いていきます。

準備

GoogleDriveから回答のスプレッドシートをダウンロードします。勝手にExcel形式に変換されて落ちてきます。

ダウンロードできたらファイルを開き、「名前をつけて保存」からCSVに変換します。 このままでもいけなくはないらしいですが、今回はCSVからやってみます。

読み込み

CSVを読み込みます。そのまま

import csv
f = open("ファイル名.csv", 'r')

として読み込むと、文字化けやら文字コードがそのままでてくるやらで大変でした。そこで、

import csv, codecs
f = open(u"ファイル名.csv", 'r', encoding='utf-8')

respondents = csv.reader(f)
header = next(csv.reader(f))

ってやると上手く読み込めます。respondentsには回答が、headerには質問内容(上表の1行目)が入ります。

また、読み込む前にCSV文字コードUTF-8に変換しておきましょう。 いまいちPythonでのやり方がわからなかったので、ターミナルでnkf -w --overwrite ファイル名ってするなり、好きなエディタの文字コード変換機能を使うなりすればいいと思います。

集計(1)

さて、やっと本題です。 リストの内容をカウントしていくわけですが、便利なライブラリがあります。名前はそのまんま「Counter」です。

from collections import Counter
cnt = Counter()

for i in range(len(header)):
    cnt[header[i]] = Counter()

とすることで、各質問内容に対するカウンターが定義されます。 回答者が1人だけなら、というか、リストが1重ならfor文以下は不要です。

あとは

for respondent in respondents:
    for i in range(len(header)):
        cnt[header[i]][respondent[i]] += 1

とすれば、カウンタcntの中に各質問の回答とその個数が辞書型で格納されています。便利ですね。

ですが、このままだとちょっとした問題があります。複数回答の扱いです。Googleフォームの複数回答CSVで見ると

…, "みかん, オレンジ", …

といったようにダブルクオーテーションで囲まれ、2つがセットになって1つとカウントされます。つまり、みかんとオレンジが好きな人、みかんとバナナが好きな人、みかんだけが好きな人は別扱いです。

ここで、みかん好きが3人とカウントされるようになるためには

for respondent in respondents:
    for i in range(len(header)):
        ress = respondent[i].split(", ")
        for res in ress:
            cnt[header[i]][res] += 1

2行目と3行目が追加したところです。セットになってるところも「, 」で区切られているので、これを無理矢理分割してリストに格納し、そのリストのそれぞれについてカウントします。

これで、複数回答にも対応した各質問の回答とその数を数えることが出来ました。

集計(2)

次は、ある質問に対して特定の回答だった場合のみカウントするようにします。 といっても

for respondent in respondents:
    # 追加
    if respondent[3] == "YES":
        continue

    for i in range(len(header)):
        ress = respondent[i].split(", ")
        for res in ress:
            cnt[header[i]][res] += 1

2, 3行目を追加しただけです。 3つ目の質問が「YES」であった時、集計をスキップします。

出力

集計結果をCSVファイルに出力していきます。

まず準備を

ff = codecs.open("ファイル名.csv", 'w', encoding='shift-jis')
csvWriter = csv.writer(ff)

わざわざshift-jisで出力しているのは、こうしないとExcelで文字化けして見れないからです。面倒くさいですね。

書き込んでいきましょう。

for i in range(len(cnt)):
    # 初期化
    question = []
    answer = []
    ansNum = []

    # 質問名書き込み
    question.append(header[i])

    # keys()はdect_keys型で返るのでlistに変換
    keys = list(cnt[header[i]].keys())
    for j in range(len(cnt[header[i]])):
        # 回答書き込み
        answer.append(keys[j])
        # 回答数書き込み
        ansNum.append(cnt[header[i]][keys[j]])

    # ファイルに書き込み
    csvWriter.writerow(question)
    csvWriter.writerow(answer)
    csvWriter.writerow(ansNum)

以上です。質問、回答、回答数がCSVファイルに質問個数分繰り返し書き込まれます。csvWriterの部分はなんかまとめて書く方法があった気がしますが、これでいけたのでいいことにしました。ごめんなさい。

まとめ

Googleフォームの結果を集計する話はいかがでしたでしょうか。 活用いただければ幸いです。

「いやお前こうしろよ」っていうツッコミもガンガンお願いします。

それでは。

[追記]

作成したプログラムのGistを公開しました。

gistcb7d4ff663d8345e47b2