今回は複数回答の集計を取り上げます。
主な情報源として「新聞、雑誌、テレビ、ラジオ」の4つの選択肢を示し、
該当するものに○をつけてもらうケースです。
どの選択肢にどれくらい「○」がついているか、その度数や割合をみます。
当Webページで紹介するスクリプトや素材データ一式は、
prast06.zip という圧縮ファイルに同梱しておきます。
zip圧縮ファイルに入っている data01.csv は
「ID, group, newspaper, magazine, tv, ragio」 の6列からなる
98行(98人分)のデータです。
乱数で生成したデータです。
groupの列は年齢層で、20, 30, 40 の整数値が書かれています。
20歳代、30歳代、40歳代の意味です。
newspaperなどの複数回答の列は、○の代わりに数値の 1 が記入されています。
選択されなかったところは空欄。
csvを表形式で示すと下のとおり(空欄は□)。
ID | group | newspaper | magazine | tv | ragio |
1 | 30 | 1 | □ | □ | □ |
2 | 40 | 1 | 1 | □ | □ |
3 | 40 | □ | 1 | □ | □ |
4 | 20 | □ | □ | 1 | □ |
もう一つ data01single.csv というのもあります。
複数回答を1つの列におさめる書き方です。
resourceという列には「newspaper,ragio」のような文字が記入されています。
○がつけられた選択肢をカンマで区切って列挙する形式。
具体的には下のとおり。
ID | group | resource |
1 | 30 | newspaper |
2 | 40 | newspaper,magazine |
3 | 40 | magazine |
4 | 20 | tv |
5 | 30 | newspaper,magazine,ragio |
この形式だと処理しにくいので前述の data01.csv の形式に変換し、
その上で集計します。
全部で98人いる中で、新聞を選択した人が何人いるかなどをみます。
これは ma_count() で行います。
まず作成する表を掲げておきます。
度数 | 割合 | |
新聞 | 52 | 53.1 |
雑誌 | 56 | 57.1 |
テレビ | 46 | 46.9 |
ラジオ | 38 | 38.8 |
総数 | 98 | 100.0 |
総数98人のうち、新聞を選んだ人が52人(53.1%)、
雑誌に○をつけた人が56人(57.1%)いたことを意味します。
前述の表を出力するスクリプトは次のとおり。
Prastクラスの ma_count() は、前述のような集計表を出力するものです。
ma は multi-anser のつもり。
dod = ma_count(clist, asc=None, value=1)
戻り値の dod は OrderedDict ですが、その key は 0 から始まる整数値です。
dod[0]
に度数と割合の DataFrame が代入されています。
第1引数の clist の指定の仕方によって dod[1]
などが
セットされるかもしれません。
引数の意味は次のとおり。
['a', 'b', 'c']
など。[['a', 'b', 'c'], ['x', 'y']]
など。dod[0]
の他に dod[1]
などが設けられる。value="y"
とする。
複数回答の列ラベルをリストで指定するのは少々面倒です。
そこで、crange() を設けてあります。
下のいずれも ['newspaper', 'magazine', 'tv', 'ragio']
を返します。
rng = psx.crange('newspaper', 'ragio') # 最初と最後の列ラベルを指定
rng = psx.crange(2, 5) # 最初と最後の列番号を指定(始点は 0)
rng = psx.crange('ragio', 'newspaper') # 順番を入れ替えても同じ
rng = psx.crange(5, 2) # 同上
行の一定範囲を指定するための irange() もあります。
使い方は crange() と同じです。
複数回答を記録するやり方として、
一つの列に○の付いた選択肢を詰め込む方法があります。
resourceという一つの列に「newspaper,tv」とか「magazine,ragio」のように
○の付いた選択肢を列記する方式です。
zip圧縮ファイルに入っている data01single.csv は、
この単一列・列記方式で書かれています。
この形式は扱いにくいので、data01.csv のような
複数列・マーク付け方式に変換してから処理します。
単一列・列記方式の DataFrame を複数列・マーク付け方式に変換するのが
single2multi() というメソッドです。
これは Prastクラスには属していません。
single2multi(dtf, mcolumn, sep=",", value=1, na=NaN, clist=None)
new_dtf = single2multi(dtf, "resource", sep=",",
value=1, na=0, clist=None)
戻り値の new_dtf には複数回答の新しい列が追加されています。
単一列の resource も残っているので、不必要なら自前で消去します。
引数の意味は次のとおり。
sep="|"
のように指定。","
とみなされる。最後の引数 clist が None であれば、選択肢の順番は「お任せ」になります。
「ragio, newspaper, tv, magazine」のような順番になるかもしれません。
「お任せ」にしたくない場合は下のようにします。
single2multi(……, clist=['newspaper', 'magazine', 'tv', 'ragio'])
なお、単一列を分解して新設された列の名前(list)は、
グローバル変数のmrange にセットされます。
single2multi() で変換してから ma_count() を用いるサンプルを掲げます。
1# ma_single2multi.py (coding: cp932) 2import pandas as pd 3import prast as ps 4ps.set_encoding("cp932") # python2用にencodingを設定 5 6dtf = pd.read_csv("data01single.csv") 7dtf = ps.single2multi(dtf, "resource", sep=",", value=1, na=0, 8 clist=['newspaper', 'magazine', 'tv', 'ragio']) 9rng = ps.mrange # resourceを分解してできた新設の列の名前 10dtf.drop("resource", axis=1, inplace=True) # resourceという列を消去 11dtf.to_csv("data02.csv", index=False) # 念のためcsvとして書き出す 12psx = ps.Prast(dtf, "data01_c.txt", "data01_i.txt", "cp932") 13dod = psx.ma_count(rng, asc=None, value=1) 14print(dod[0])
single2multi() と逆の変換を行う multi2single() もあります。
複数列・マーク付け方式→単一列・列記方式の変換です。
multi2single(dtf, clist, mcolumn, sep=",", value=1)
new_dtf = multi2single(dtf, ['newspaper', 'magazine', 'tv', 'ragio'],
"resource", sep=",", value=1)
参考までサンプルスクリプトを掲げておきます。
1# ma_multi2single.py (coding: cp932) 2import pandas as pd 3import prast as ps 4ps.set_encoding("cp932") # python2用にencodingを設定 5 6dtf = pd.read_csv("data01.csv") 7rng = ['newspaper', 'magazine', 'tv', 'ragio'] 8dtf = ps.multi2single(dtf, rng, "resource", sep=",", value=1) 9dtf.drop(rng, axis=1, inplace=True) # 複数回答の複数列を消去 10dtf.to_csv("data03.csv", index=False) # csvとして書き出す
data01.csv には group(年齢層)があります。単一回答です。
各年齢層ごとに複数回答がどれくらい選ばれているかを集計するため
ma_table() を設けてあります。
ma_table() は、戻り値として4つの DataFrame を返します。
そのうちの1つは次のとおり。
新聞 | 雑誌 | テレビ | ラジオ | 総数 | |
20代 | 13 | 17 | 12 | 12 | 31 |
30代 | 24 | 17 | 18 | 12 | 34 |
40代 | 15 | 22 | 16 | 14 | 33 |
合計 | 52 | 56 | 46 | 38 | 98 |
最右列の「総数」は、合計値ではなく、各年齢層の人数の総数です。
一方、最下行の「合計」は素直な合計値です。
年齢層が単一回答なので合計値が意味を持ちます。
得られる4つの表は次のとおり。
pct1の表は下のようになります。
新聞 | 雑誌 | テレビ | ラジオ | 総数 | |
20代 | 41.9 | 54.8 | 38.7 | 38.7 | 100.0 |
30代 | 70.6 | 50.0 | 52.9 | 35.3 | 100.0 |
40代 | 45.5 | 66.7 | 48.5 | 42.4 | 100.0 |
合計 | 53.1 | 57.1 | 46.9 | 38.8 | 100.0 |
単一回答と複数回答の組み合わせ集計を行うスクリプトは次のとおり。
1# ma_table.py (coding: cp932) 2import pandas as pd 3from prast import Prast 4 5dtf = pd.read_csv("data01.csv") 6psx = Prast(dtf, "data01_c.txt", "data01_i.txt", "cp932") 7rng = psx.crange(2, 5) 8dod = psx.ma_table(rng, "group", value=1) 9for key in dod.keys(): 10 print(key) 11 print(dod[key]) 12 print('')
ma_table() は、第1引数に複数回答の列ラベル群、
第2引数に単一回答の列ラベルを指定します。
dod = ma_table(rng, gkey, value=1)
第3引数の value は、複数回答の列において
選択されたものに割り当てられている値(デフォルトは数値の1)です。
集計の際、この value の値のセルをカウントします。
戻り値は OrderedDict で、4つのDataFrame がセットされています。
これについては4つの表(度数と割合の表)として既に書いたので省略。
「新聞」に○をつけた人のうち、どれくらいの人が「雑誌」にも○をつけたかなどをみます。
それを行うため ma_rel() というメソッドを設けました。
下のような表を作成します。
列と行のどちらも、複数回答の選択肢の名前です。
新聞 | 雑誌 | テレビ | ラジオ | |
新聞 | 52 | 29 | 21 | 23 |
雑誌 | 29 | 56 | 26 | 20 |
テレビ | 21 | 26 | 46 | 9 |
ラジオ | 23 | 20 | 9 | 38 |
1行目は「新聞」に○をつけた人の情報です。
「1行・2列」のセルは「新聞」と「雑誌」の交差点ですが、
「新聞」と「雑誌」の両方に○をつけた人数を示します。
「1行・1列」は「新聞」と「新聞」の交差点で、
要するに「新聞」を選んだ人の総数を意味します。
この表は、行と列を入れ替えても同じものになります。
この度数の表についてパーセンテージを示す場合、2種類が考えられます。
1行目は「新聞」を選んだ人を100%とする割合、
2行目は「雑誌」に○をつけた人を100%とする割合…… とする表。
もう一つは、回答者総数(98人)を100%とする表です。
ma_rel() は、度数表と2つのパーセンテージの表(合計3つ)を作成します。
参考まで、下に2種類のパーセンテージの表を掲げておきます。
新聞 | 雑誌 | テレビ | ラジオ | |
新聞 | 100.0 | 55.8 | 40.4 | 44.2 |
雑誌 | 51.8 | 100.0 | 46.4 | 35.7 |
テレビ | 45.7 | 56.5 | 100.0 | 19.6 |
ラジオ | 60.5 | 52.6 | 23.7 | 100.0 |
上記は、左上から右下の対角線がいずれも 100%になっています。
N=98 | 新聞 | 雑誌 | テレビ | ラジオ |
新聞 | 53.1 | 29.6 | 21.4 | 23.5 |
雑誌 | 29.6 | 57.1 | 26.5 | 20.4 |
テレビ | 21.4 | 26.5 | 46.9 | 9.2 |
ラジオ | 23.5 | 20.4 | 9.2 | 38.8 |
左上端の「N=98」が、分母になった「総数」を示します。
ma_rel() を用いるサンプルスクリプトを掲げます。
ma_rel() の引数は2つです。
dod = ma_rel(clist, value=1)
第1引数は列ラベルのリスト(複数回答の列ラベル)。
第2引数は○に与えられている値です。
戻り値は OrderedDict で、3つの DataFrame がセットされています。
今回はこれで終了です。
次回、複数回答の簡単な分析について書きたいとおもいます。
〜 以上 〜
Copyright (C) T. Yoshiizumi, 2018 All rights reserved.