12  データの読み込み

政治学で用いるデータの多くは、ウェブサイト上に公開されているデータです。今回は公開されているデータを読み込む方法を紹介します。

12.1 使用するパッケージ

Rでデータを読み込む場合、標準関数を用いるか、tidyverseに含まれるパッケージreadrを使うことが多いです。

R
library(tidyverse)

Pythonの場合、pandasがデファクト・スタンダードですが、最近はpolarsも人気ではないかと思います。

Python
import pandas as pd
import polars as pl

12.2 データの形式と読み込み

しかし、本命はネット上で公開されているデータなどを読み込むことではないかと思います。データには形式があり、それに応じてデータを読み込む必要があります。データの形式はファイルの拡張子を見れば分かります。

  • 例えば、sample.csvというファイルであれば、sampleがファイル名で、.以降のcsvが拡張子です。このファイルはcsvファイルであることが分かります。
  • もしPCで拡張子が表示されていない設定であれば、表示するように設定することを勧めます。

以下では、dataフォルダに入っているxxxというファイルを読み込み、df_sampleというオブジェクトにするコードを紹介します。

12.2.1 csvファイル

ここでは、代表的なデータの形式と読み込み方法を紹介します。表形式のデータと言われると、エクセルファイルを思い浮かべると思いますが、研究の世界ではcsvファイルやtsvファイルが多いように思います。

csvとは”comma-separated values”の略で、その名の通り「コンマ,」で区切られたファイルです。

R (base)
df_sample <- read.csv("data/xxx.csv")
R (tidyverse)
df_sample <- read_csv("data/xxx.csv")
Python (pandas)
df_sample = pd.read_csv("data/xxx.csv")
Python (polars)
df_sample = pl.read_csv("data/xxx.csv")

12.2.1.1 Qualtrics

政治学ではサーベイ(実験)を行う際にはQualtricsというサービスを使うことが多いです。RではqualtRicsというパッケージを使うことで、サーベイ結果のcsvファイルを読み込めます。

R (qualtRics)
library(qualtRics)

df_sample <- read_survey("data/xxx.csv")

12.2.2 tsvファイル

一方で、tsvは「タブ」で区切られています。

R (base)
df_sample <- read.csv("data/xxx.csv", sep="\t")
R (tidyverse)
df_sample <- read_tsv("data/xxx.tsv")
Python (pandas)
df_sample = pd.read_csv("data/xxx.csv", sep="\t")
Python (polars)
df_sample = pl.read_csv("data/xxx.csv", separator="\t")

tidyverseには専用の関数がありますが、それ以外ではタブ区切りであることを指定する必要があります。

  • \tはタブの正規表現 (regular expression) です。

12.2.3 xls[x]ファイル:Excel

Excelファイルを読み込む場合、Rではreadrというパッケージを使います。

  • Excelファイルの拡張子はxlsまたはxlsxです。
R (readxl)
library(readxl)

df_sample <- read_excel("data/xxx.xlsx")
Python (pandas)
df_sample = pd.read_excel("data/xxx.xlsx")
  • openpyxlxlrdをインストールしておく必要があります。
Python (polars)
df_sample = pl.read_excel("data/xxx.xlsx")
  • fastexcelxlsx2csvをインストールしておく必要があります。

12.2.4 dtaファイル:Stata

政治学や経済学などではStataという統計分析ソフトを使うこともあります。Stata専用のデータ形式はdtaファイルと呼びます。

R (tidyverse)
library(haven)

df_sample <- read_dta("data/xxx.dta")
Python (pandas)
df_sample = pd.read_stata("data/xxx.dta")

政治学だとめったに遭遇しませんが、おそらく心理学や医学ではSASという統計ソフトを使うことがあり、専用のファイルを読み込む関数もあります。

12.3 データの読み込み実践

まずは、キレイなデータを読み込みたいと思います。政治学において民主主義は避けて通ることのできない概念であり、様々なデータセットがあります。その代表的なものとしてPolityというものがあります。

  • “Polity5 Annual Time-Series, 1946-2018”のエクセルデータを作業ディレクトリ内のdataフォルダに保存します。

それでは、エクセルデータを読み込みます。

R (readxl)
library(readxl)

df_polity <- read_excel("data/p5v2018.xls")

head(df_polity)
# A tibble: 6 × 37
     p5   cyear ccode scode country      year  flag fragment democ autoc polity
  <dbl>   <dbl> <dbl> <chr> <chr>       <dbl> <dbl>    <dbl> <dbl> <dbl>  <dbl>
1     0 7001800   700 AFG   Afghanistan  1800     0       NA     1     7     -6
2     0 7001801   700 AFG   Afghanistan  1801     0       NA     1     7     -6
3     0 7001802   700 AFG   Afghanistan  1802     0       NA     1     7     -6
4     0 7001803   700 AFG   Afghanistan  1803     0       NA     1     7     -6
5     0 7001804   700 AFG   Afghanistan  1804     0       NA     1     7     -6
6     0 7001805   700 AFG   Afghanistan  1805     0       NA     1     7     -6
# ℹ 26 more variables: polity2 <dbl>, durable <dbl>, xrreg <dbl>, xrcomp <dbl>,
#   xropen <dbl>, xconst <dbl>, parreg <dbl>, parcomp <dbl>, exrec <dbl>,
#   exconst <dbl>, polcomp <dbl>, prior <dbl>, emonth <dbl>, eday <dbl>,
#   eyear <dbl>, eprec <dbl>, interim <dbl>, bmonth <dbl>, bday <dbl>,
#   byear <dbl>, bprec <dbl>, post <dbl>, change <dbl>, d5 <dbl>, sf <dbl>,
#   regtrans <dbl>
Python (pandas)
df_polity = pd.read_excel("data/p5v2018.xls")

df_polity.head()
   p5    cyear  ccode scode      country  ...  post  change   d5  sf  regtrans
0   0  7001800    700   AFG  Afghanistan  ...  -6.0    88.0  1.0 NaN       NaN
1   0  7001801    700   AFG  Afghanistan  ...   NaN     NaN  NaN NaN       NaN
2   0  7001802    700   AFG  Afghanistan  ...   NaN     NaN  NaN NaN       NaN
3   0  7001803    700   AFG  Afghanistan  ...   NaN     NaN  NaN NaN       NaN
4   0  7001804    700   AFG  Afghanistan  ...   NaN     NaN  NaN NaN       NaN

[5 rows x 37 columns]
Python (polars)
df_polity = pl.read_excel("data/p5v2018.xls")

df_polity.head()
shape: (5, 37)
p5 cyear ccode scode country year flag fragment democ autoc polity polity2 durable xrreg xrcomp xropen xconst parreg parcomp exrec exconst polcomp prior emonth eday eyear eprec interim bmonth bday byear bprec post change d5 sf regtrans
i64 i64 i64 str str i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64
0 7001800 700 "AFG" "Afghanistan" 1800 0 null 1 7 -6 -6 null 3 1 1 1 3 3 1 1 6 null null null null null null 1 1 1800 1 -6 88 1 null null
0 7001801 700 "AFG" "Afghanistan" 1801 0 null 1 7 -6 -6 null 3 1 1 1 3 3 1 1 6 null null null null null null null null null null null null null null null
0 7001802 700 "AFG" "Afghanistan" 1802 0 null 1 7 -6 -6 null 3 1 1 1 3 3 1 1 6 null null null null null null null null null null null null null null null
0 7001803 700 "AFG" "Afghanistan" 1803 0 null 1 7 -6 -6 null 3 1 1 1 3 3 1 1 6 null null null null null null null null null null null null null null null
0 7001804 700 "AFG" "Afghanistan" 1804 0 null 1 7 -6 -6 null 3 1 1 1 3 3 1 1 6 null null null null null null null null null null null null null null null
  • Google Colaboratoryを使っている場合はパスの先頭にdrive/MyDrive/を付けます。つまり、"drive/MyDrive/data/p5v2018.xls"とします。

ところで、それぞれNANaNnullとありますが、これらは欠損値 (missing value) を意味しています。欠損値とは何かしらの理由で変数の値が測定されていないことを意味します。

  • 例えば、その年にその国が独立していない場合などは民主主義を測定できません。

12.3.1 行のスキップ

政治学で使用するデータの多くは上記のようなコードで読み込みが可能だと思います。しかし、実際には様々な理由から、単にデータを読み込むだけでは分析できないことがあります。以下では、実際のデータを用いつつ、どのような問題に遭遇しうるのか、その際にどのように対処すれば良いかを学びます。

まずは、World Bank Open Dataのデータを読み込んでみましょう。

  • 例えば、女性人口 (Population, female) で検索をし、右側にあるDownloadのCSVをクリックします。
  • xipファイルがダウンロードされるので、それを適当なフォルダ(例えばダウンロードフォルダ)に保存し、解凍します。
  • その中に、長いファイル名のファイルが3つありますが、APIから始まるファイルが目当てのファイルです。
  • このファイルを作業ディレクトリ内のdataフォルダにコピーをします。
  • ファイル名が分かりにくいので、分かりやすい名前(例えば、wb_pop_fem.csv)に変えておきます。

それでは、データを読み込んでみます。

R (tidyverse)
df_pop_fem <- read_csv("data/wb_pop_fem.csv")

head(df_pop_fem)
# A tibble: 6 × 3
  `Data Source`               `World Development Indicators` ...3               
  <chr>                       <chr>                          <chr>              
1 Last Updated Date           2024-03-28                      <NA>              
2 Country Name                Country Code                   "Indicator Name,In…
3 Aruba                       ABW                            "Population, femal…
4 Africa Eastern and Southern AFE                            "Population, femal…
5 Afghanistan                 AFG                            "Population, femal…
6 Africa Western and Central  AFW                            "Population, femal…
Python (pandas)
df_pop_fem = pd.read_csv("data/wb_pop_fem.csv")
pandas.errors.ParserError: Error tokenizing data. C error: Expected 3 fields in line 5, saw 69
Python (polars)
df_pop_fem = pl.read_csv("data/wb_pop_fem.csv")
polars.exceptions.ComputeError: found more fields than defined in 'Schema'

Consider setting 'truncate_ragged_lines=True'.

さて、Pythonではエラーが生じました。また、Rでも肝心の女性の人口データが含まれていません。

なぜこのようなことになってしまったのか、元のcsvファイルをエクセルなどの表計算ソフトで見てみます。すると、最初の4行ほどはデータソースや更新日などが書かれており、目当てのデータは5行目以降にあることが分かります。

R/Pythonは素直なので、上から順にデータを読み込みます。Rはおそらくこのデータは2,3列しかないだろうと思って読み込んだのでしょう。Pythonは2列しかないと思っていたら5行目でそれ以上のデータと遭遇してエラーを出してしまったのでしょう。

したがって、このような場合は「5行目から読んでね(4行目までは無視してね)」とR/Pythonにお願いする必要があります。

R (tidyverse)
df_pop_fem <- read_csv("data/wb_pop_fem.csv", skip = 4)

head(df_pop_fem)
# A tibble: 6 × 69
  `Country Name`  `Country Code` `Indicator Name` `Indicator Code` `1960` `1961`
  <chr>           <chr>          <chr>            <chr>             <dbl>  <dbl>
1 Aruba           ABW            Population, fem… SP.POP.TOTL.FE.… 2.78e4 2.84e4
2 Africa Eastern… AFE            Population, fem… SP.POP.TOTL.FE.… 6.59e7 6.76e7
3 Afghanistan     AFG            Population, fem… SP.POP.TOTL.FE.… 4.15e6 4.23e6
4 Africa Western… AFW            Population, fem… SP.POP.TOTL.FE.… 4.88e7 4.99e7
5 Angola          AGO            Population, fem… SP.POP.TOTL.FE.… 2.67e6 2.70e6
6 Albania         ALB            Population, fem… SP.POP.TOTL.FE.… 7.85e5 8.09e5
# ℹ 63 more variables: `1962` <dbl>, `1963` <dbl>, `1964` <dbl>, `1965` <dbl>,
#   `1966` <dbl>, `1967` <dbl>, `1968` <dbl>, `1969` <dbl>, `1970` <dbl>,
#   `1971` <dbl>, `1972` <dbl>, `1973` <dbl>, `1974` <dbl>, `1975` <dbl>,
#   `1976` <dbl>, `1977` <dbl>, `1978` <dbl>, `1979` <dbl>, `1980` <dbl>,
#   `1981` <dbl>, `1982` <dbl>, `1983` <dbl>, `1984` <dbl>, `1985` <dbl>,
#   `1986` <dbl>, `1987` <dbl>, `1988` <dbl>, `1989` <dbl>, `1990` <dbl>,
#   `1991` <dbl>, `1992` <dbl>, `1993` <dbl>, `1994` <dbl>, `1995` <dbl>, …
Python (pandas)
df_pop_fem = pd.read_csv("data/wb_pop_fem.csv", skiprows=4)

df_pop_fem.head()
                  Country Name Country Code  ... 2023 Unnamed: 68
0                        Aruba          ABW  ...  NaN         NaN
1  Africa Eastern and Southern          AFE  ...  NaN         NaN
2                  Afghanistan          AFG  ...  NaN         NaN
3   Africa Western and Central          AFW  ...  NaN         NaN
4                       Angola          AGO  ...  NaN         NaN

[5 rows x 69 columns]
Python (polars)
df_pop_fem = pl.read_csv("data/wb_pop_fem.csv", skip_rows=4)

df_pop_fem.head()
shape: (5, 69)
Country Name Country Code Indicator Name Indicator Code 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023
str str str str i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 str str
"Aruba" "ABW" "Population, fe… "SP.POP.TOTL.FE… 27773 28380 28820 29218 29570 29875 30135 30253 30232 30166 30063 29927 29953 30229 30595 30972 31245 31416 31584 31749 31909 32121 32389 32659 32886 33008 33007 32904 32788 32892 33480 34657 35941 37137 38437 39724 41014 42336 43688 45050 46269 47178 47831 48374 48877 49414 50016 50636 51272 51919 52484 52980 53480 53953 54403 54828 55224 55591 55935 56254 56373 56330 56272 "" null
"Africa Eastern… "AFE" "Population, fe… "SP.POP.TOTL.FE… 65853220 67606287 69457112 71375643 73386167 75478396 77610073 79810945 82111287 84493601 86968714 89504801 92051419 94694181 97478670 100339888 103289004 106237590 109415983 112834021 116060576 119525759 123410049 127333314 131344567 135563206 139816011 144066893 148288335 152522362 156942214 161298074 165609524 170167926 174762745 179486372 184468529 189280003 194009070 198959676 204048614 209257664 214635664 220167814 225898442 231830259 237997868 244435307 251105628 257956460 265000967 272174714 279546577 287224924 295089133 303195897 311387401 319637365 328159112 336930970 345889868 354855221 363834524 "" null
"Afghanistan" "AFG" "Population, fe… "SP.POP.TOTL.FE… 4145945 4233771 4326881 4424511 4526691 4634341 4745981 4861918 4983086 5108507 5239568 5372747 5509781 5655304 5803603 5948268 6083166 6214979 6342838 6373547 6136856 5490160 4973968 4916351 5074600 5225679 5207273 5152650 5188060 5334609 5346409 5372208 6028939 7000119 7722096 8199445 8537421 8871958 9217591 9595036 9727541 9793166 10438055 11247647 11690825 12109086 12614497 12835340 13088192 13557331 13949295 14468875 15067373 15594637 16172321 16682054 17115346 17614722 18136922 18679089 19279930 19844584 20362329 "" null
"Africa Western… "AFW" "Population, fe… "SP.POP.TOTL.FE… 48802898 49850088 50928609 52044907 53196730 54389295 55621877 56890201 58204276 59560501 60963620 62404746 63900687 65482730 67160750 68943269 70786681 72718234 74770813 76909670 79104037 81359426 83714354 85996392 88238093 90605997 93047700 95556172 98139171 100824162 103478502 106184462 109071980 111968903 114896750 117979287 121143186 124399328 127775360 131211380 134795501 138546839 142408066 146370538 150463219 154696476 159035017 163481052 168058833 172782717 177645233 182657978 187755307 192900081 198163527 203513873 208980433 214578994 220253839 226004857 231877590 237813580 243821774 "" null
"Angola" "AGO" "Population, fe… "SP.POP.TOTL.FE… 2670229 2704394 2742689 2779473 2812590 2838939 2856740 2867926 2879001 2902120 2953347 3032948 3132441 3244749 3362438 3483416 3606782 3735823 3872130 4014347 4164145 4321167 4485276 4656894 4834820 5018620 5206761 5396035 5588733 5787505 5991207 6199060 6408303 6621767 6845622 7077381 7315200 7561436 7813123 8071413 8339311 8619083 8912191 9219638 9545020 9886765 10244381 10620174 11013001 11422969 11853530 12303450 12770743 13252938 13746371 14248799 14764575 15293335 15828040 16370553 16910989 17452283 17998220 "" null

無事にデータを読み込むことができました。ここから得られる教訓は、データを読み込む前に表計算ソフトでどのようなデータなのか確認すべしということでしょう。

12.3.2 シートの選択

続いて、ストックホルム国際平和研究所のSIPRI Military Expenditure Databaseを扱います。

  • リンクをクリックしてデータを作業ディレクトリ内のdataフォルダに保存します。

先程の教訓を活かして、まずは表計算ソフトでこのファイルを開きます。すると、英語で説明が書かれたページが表示されます。

エクセルファイルは一つのファイルに複数のシート(データフレーム)が含まれていることがあります。したがって、その場合はどのシートを読み込むかを指定する必要があります。試しに、実質USドルで計算された5つ目のシートを読み込みます。

また、5つ目のシートを見てみると最初の5行は説明書きのようなので、スキップします。

R (readxl)
library(readxl)

df_sipri <- read_excel("data/SIPRI-Milex-data-1949-2022.xlsx", sheet = 5, skip = 5)

head(df_sipri)
# A tibble: 6 × 77
  Country      ...2  Notes `1949.0` `1950.0` `1951.0` `1952.0` `1953.0` `1954.0`
  <chr>        <lgl> <chr> <chr>    <chr>    <chr>    <chr>    <chr>    <chr>   
1 <NA>         NA    <NA>  <NA>     <NA>     <NA>     <NA>     <NA>     <NA>    
2 Africa       NA    <NA>  <NA>     <NA>     <NA>     <NA>     <NA>     <NA>    
3 North Africa NA    <NA>  <NA>     <NA>     <NA>     <NA>     <NA>     <NA>    
4 Algeria      NA    §4    xxx      xxx      xxx      xxx      xxx      xxx     
5 Libya        NA    द16 xxx      xxx      ...      ...      ...      ...     
6 Morocco      NA    §17   xxx      xxx      xxx      xxx      xxx      xxx     
# ℹ 68 more variables: `1955.0` <chr>, `1956.0` <chr>, `1957.0` <chr>,
#   `1958.0` <chr>, `1959.0` <chr>, `1960.0` <chr>, `1961.0` <chr>,
#   `1962.0` <chr>, `1963.0` <chr>, `1964.0` <chr>, `1965.0` <chr>,
#   `1966.0` <chr>, `1967.0` <chr>, `1968.0` <chr>, `1969.0` <chr>,
#   `1970.0` <chr>, `1971.0` <chr>, `1972.0` <chr>, `1973.0` <chr>,
#   `1974.0` <chr>, `1975.0` <chr>, `1976.0` <chr>, `1977.0` <chr>,
#   `1978.0` <chr>, `1979.0` <chr>, `1980.0` <chr>, `1981.0` <chr>, …
Python (pandas)
df_sipri = pd.read_excel("data/SIPRI-Milex-data-1949-2022.xlsx", sheet_name=5, skiprows=5)

df_sipri.head()
        Country  Notes 1949  ...        2020         2021         2022
0           NaN    NaN  NaN  ...         NaN          NaN          NaN
1        Africa    NaN  NaN  ...         NaN          NaN          NaN
2  North Africa    NaN  NaN  ...         NaN          NaN          NaN
3       Algeria     §4  xxx  ...  9708.27744  9112.461105  9145.810174
4         Libya  द16  xxx  ...         ...          ...          ...

[5 rows x 76 columns]
Python (polars)
df_sipri = pl.read_excel("data/SIPRI-Milex-data-1949-2022.xlsx", sheet_id=5, read_options={"skip_rows": 5})

df_sipri.head()
shape: (5, 76)
Country Notes 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022
str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str str
"Africa" null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
"North Africa" null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
"Algeria" "§4" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "..." "..." "..." "..." "..." "..." "..." "234.875985" "219.434678" "215.133118" "208.220940" "215.742463" "413.599801" "461.022683" "642.532765" "560.729351" "607.406682" "600.773471" "683.327939" "607.328128" "701.198007" "704.831389" "610.182410" "622.034094" "615.542127" "601.651385" "642.721150" "657.986141" "1101.032432" "1183.864801" "1440.243493" "1395.429481" "1588.840569" "1910.994943" "2021.120506" "2133.027701" "2475.100274" "2709.025608" "2768.307740" "2708.645105" "3080.937162" "3225.387723" "3306.186349" "3879.058547" "4519.638056" "4908.797561" "5194.999271" "7434.910242" "7823.704814" "8450.873651" "9732.621963" "10182.147187" "10212.538248" "9671.777933" "9275.706188" "10006.914126" "9773.554762" "9112.461105" "8776.364725"
"Libya" "द16" "xxx" "xxx" "..." "..." "..." "..." "..." "..." "..." "..." "..." "..." "..." "..." "..." "62.239411" "75.739505" "135.605176" "171.736926" "205.401564" "280.364831" "501.713486" "517.782969" "399.804189" "496.864250" "660.244648" "403.379454" "433.595285" "599.712512" "705.411019" "877.901730" "1006.758017" "469.762633" "542.251381" "..." "..." "..." "..." "..." "..." "..." "..." "..." "..." "..." "..." "528.148467" "595.753213" "460.005767" "492.339926" "481.663213" "619.030119" "770.484367" "1006.128971" "991.116581" "872.043438" "820.739134" "1240.400997" "..." "..." "..." "2691.266837" "3509.174752" "3246.886855" "..." "..." "..." "..." "..." "..." "..." "..."
"Morocco" "§17" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "xxx" "119.561947" "174.296160" "231.988959" "270.419973" "269.797363" "307.693292" "326.567713" "429.706446" "386.061343" "336.729958" "365.821285" "381.660589" "491.011780" "445.838272" "460.681190" "552.386269" "610.999174" "694.413605" "818.316780" "1201.617167" "1686.646799" "1934.233958" "1722.805411" "1726.670724" "1987.294925" "2025.512311" "2098.786842" "1527.477606" "1721.964873" "1722.974496" "1859.410193" "2010.669934" "1974.552450" "2073.654577" "2057.185887" "2170.432946" "2228.159258" "2052.130321" "2046.648979" "2143.497749" "2169.058500" "1837.788653" "1390.760784" "2516.231872" "2394.040085" "2535.872578" "2464.704546" "2557.771063" "2582.189542" "2659.230192" "2966.110340" "3168.016273" "3390.448538" "3415.165311" "3660.789360" "4182.250761" "4146.897151" "3828.729050" "3852.059058" "3965.368975" "3993.067756" "4076.773137" "5225.571603" "5378.366535" "5368.334058"
  • pl.read_csv()のときとスキップの仕方が異なる点に注意してください。

ややツッコミどころはありますが、一応、それなりにデータが読み込みめているようです。

12.3.3 欠損値の指定

残念ながら、まだこれだけでは分析に耐えるデータではありません。1つ目の問題は、謎のxxx...です。改めて元のデータを見てみると、4行目に”“. .” = data unavailable. “xxx” = country did not exist or was not independent during all or part of the year in question.”と書いてあります。すなわち、これらは欠損値を示していると考えられます。

したがって、データを読み込む際にはこれらを欠損値であることをR/Pythonに教えてあげる必要があります。

R (readxl)
library(readxl)

df_sipri <- read_excel("data/SIPRI-Milex-data-1949-2022.xlsx", sheet = 5, skip = 5, na = c("xxx", "..."))

head(df_sipri)
# A tibble: 6 × 77
  Country      ...2  Notes `1949.0` `1950.0` `1951.0` `1952.0` `1953.0` `1954.0`
  <chr>        <lgl> <chr>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
1 <NA>         NA    <NA>        NA       NA       NA       NA       NA       NA
2 Africa       NA    <NA>        NA       NA       NA       NA       NA       NA
3 North Africa NA    <NA>        NA       NA       NA       NA       NA       NA
4 Algeria      NA    §4          NA       NA       NA       NA       NA       NA
5 Libya        NA    द16       NA       NA       NA       NA       NA       NA
6 Morocco      NA    §17         NA       NA       NA       NA       NA       NA
# ℹ 68 more variables: `1955.0` <dbl>, `1956.0` <dbl>, `1957.0` <dbl>,
#   `1958.0` <dbl>, `1959.0` <dbl>, `1960.0` <dbl>, `1961.0` <dbl>,
#   `1962.0` <dbl>, `1963.0` <dbl>, `1964.0` <dbl>, `1965.0` <dbl>,
#   `1966.0` <dbl>, `1967.0` <dbl>, `1968.0` <dbl>, `1969.0` <dbl>,
#   `1970.0` <dbl>, `1971.0` <dbl>, `1972.0` <dbl>, `1973.0` <dbl>,
#   `1974.0` <dbl>, `1975.0` <dbl>, `1976.0` <dbl>, `1977.0` <dbl>,
#   `1978.0` <dbl>, `1979.0` <dbl>, `1980.0` <dbl>, `1981.0` <dbl>, …
Python (pandas)
df_sipri = pd.read_excel("data/SIPRI-Milex-data-1949-2022.xlsx", sheet_name=5, skiprows=5, na_values=["xxx", "..."])

df_sipri.head()
        Country  Notes  1949  ...        2020         2021         2022
0           NaN    NaN   NaN  ...         NaN          NaN          NaN
1        Africa    NaN   NaN  ...         NaN          NaN          NaN
2  North Africa    NaN   NaN  ...         NaN          NaN          NaN
3       Algeria     §4   NaN  ...  9708.27744  9112.461105  9145.810174
4         Libya  द16   NaN  ...         NaN          NaN          NaN

[5 rows x 76 columns]
Python (polars)
df_sipri = pl.read_excel("data/SIPRI-Milex-data-1949-2022.xlsx", sheet_id=5, read_options={"skip_rows": 5, "null_values": ["xxx", "..."]})

df_sipri.head()
shape: (5, 76)
Country Notes 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022
str str f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64
"Africa" null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
"North Africa" null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null
"Algeria" "§4" null null null null null null null null null null null null null null null null null null null null 234.875985 219.434678 215.133118 208.22094 215.742463 413.599801 461.022683 642.532765 560.729351 607.406682 600.773471 683.327939 607.328128 701.198007 704.831389 610.18241 622.034094 615.542127 601.651385 642.72115 657.986141 1101.032432 1183.864801 1440.243493 1395.429481 1588.840569 1910.994943 2021.120506 2133.027701 2475.100274 2709.025608 2768.30774 2708.645105 3080.937162 3225.387723 3306.186349 3879.058547 4519.638056 4908.797561 5194.999271 7434.910242 7823.704814 8450.873651 9732.621963 10182.147187 10212.538248 9671.777933 9275.706188 10006.914126 9773.554762 9112.461105 8776.364725
"Libya" "द16" null null null null null null null null null null null null null null null 62.239411 75.739505 135.605176 171.736926 205.401564 280.364831 501.713486 517.782969 399.804189 496.86425 660.244648 403.379454 433.595285 599.712512 705.411019 877.90173 1006.758017 469.762633 542.251381 null null null null null null null null null null null null 528.148467 595.753213 460.005767 492.339926 481.663213 619.030119 770.484367 1006.128971 991.116581 872.043438 820.739134 1240.400997 null null null 2691.266837 3509.174752 3246.886855 null null null null null null null null
"Morocco" "§17" null null null null null null null 119.561947 174.29616 231.988959 270.419973 269.797363 307.693292 326.567713 429.706446 386.061343 336.729958 365.821285 381.660589 491.01178 445.838272 460.68119 552.386269 610.999174 694.413605 818.31678 1201.617167 1686.646799 1934.233958 1722.805411 1726.670724 1987.294925 2025.512311 2098.786842 1527.477606 1721.964873 1722.974496 1859.410193 2010.669934 1974.55245 2073.654577 2057.185887 2170.432946 2228.159258 2052.130321 2046.648979 2143.497749 2169.0585 1837.788653 1390.760784 2516.231872 2394.040085 2535.872578 2464.704546 2557.771063 2582.189542 2659.230192 2966.11034 3168.016273 3390.448538 3415.165311 3660.78936 4182.250761 4146.897151 3828.72905 3852.059058 3965.368975 3993.067756 4076.773137 5225.571603 5378.366535 5368.334058

先程までxxx...であったところが欠損値になっていることが分かります。必ずしもエラーが出なかったとしても問題がないというわけではない、というのがもう一つの教訓でしょうか。

これでもまだ直すべき点はあるのですが、それはデータの加工として扱いたいと思います。

12.3.4 文字化けの対処

最後に、日本語を含むデータを用いて文字化けに対処したいと思います。まずは、東京大学谷口研究室・朝日新聞社共同調査の2017年衆院選の有権者調査のデータをダウンロードします。

表計算ソフトで開くと、おそらくMac/Linuxユーザは都道府県などが文字化けしているのではないでしょうか。大雑把に言ってしまうとWindowsで作ったファイルはMac/Linuxで文字化けを起こし、その逆もまた然りです。

その場合、文字データの処理方法(エンコード)を適切に設定することで、文字化けを回避することができます。Windowsで作成された日本語データはShift-JIS(あるいはCP932)という形式でエンコードされるので、そのように指定します。

  • ついでに99が無回答なので欠損値としておきます。
R (tidyverse)
df_voter2017 <- read_csv("data/2017UTASV20200326.csv", locale = locale(encoding = "Shift-JIS"), na = "99")

head(df_voter2017)
# A tibble: 6 × 137
     ID PREFNAME CITY    PREFEC HRDIST    Q1    Q2    Q3    Q4  Q5_1  Q5_2  Q5_3
  <dbl> <chr>    <chr>    <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     4 北海道   札幌市…      1      1     2     1     4     1     6     2     5
2     6 北海道   札幌市…      1      1     2     4     1     4     6     2     7
3     7 北海道   札幌市…      1      1     1    66    66    66    66    66    66
4    10 北海道   札幌市…      1      1     1    66    66    66    66    66    66
5    11 北海道   札幌市…      1      3     2     1     2     1     6     5     1
6    12 北海道   札幌市…      1      3     2     6     2     6    10     5    11
# ℹ 125 more variables: Q6_1 <dbl>, Q6_2 <dbl>, Q6_3 <dbl>, Q7_1 <dbl>,
#   Q7_2 <dbl>, Q7_3 <dbl>, Q7_4 <dbl>, Q7_5 <dbl>, Q7_6 <dbl>, Q8 <dbl>,
#   Q9_1 <dbl>, Q9_2 <dbl>, Q9_3 <dbl>, Q9_4 <dbl>, Q9_5 <dbl>, Q9_6 <dbl>,
#   Q9_7 <dbl>, Q9_8 <dbl>, Q9_9 <dbl>, Q10 <dbl>, Q11_1 <dbl>, Q11_2 <dbl>,
#   Q12 <dbl>, Q13_1 <dbl>, Q13_2 <dbl>, Q13_3 <dbl>, Q13_4 <dbl>, Q13_5 <dbl>,
#   Q13_6 <dbl>, Q13_7 <dbl>, Q13_8 <dbl>, Q13_9 <dbl>, Q13_10 <dbl>,
#   Q14 <dbl>, Q15_1 <dbl>, Q15_2 <dbl>, Q16 <dbl>, Q17_1 <dbl>, Q17_2 <dbl>, …
Python (pandas)
df_voter2017 = pd.read_csv("data/2017UTASV20200326.csv", encoding="Shift-JIS", na_values="99")

df_voter2017.head()
   ID PREFNAME    CITY  PREFEC  HRDIST  ...  Q19FA  Q26_2FA  Q26_3FA  F3FA  F4FA
0   4      北海道  札幌市中央区       1       1  ...    NaN      NaN      NaN   NaN   NaN
1   6      北海道  札幌市中央区       1       1  ...    NaN      NaN      NaN   NaN   NaN
2   7      北海道  札幌市中央区       1       1  ...    NaN      NaN      NaN   NaN   NaN
3  10      北海道  札幌市中央区       1       1  ...    NaN      NaN      NaN   NaN   NaN
4  11      北海道  札幌市豊平区       1       3  ...    NaN      NaN      NaN  大学中退   NaN

[5 rows x 137 columns]
Python (polars)
df_voter2017 = pl.read_csv("data/2017UTASV20200326.csv", encoding="Shift-JIS", null_values="99")

df_voter2017.head()
shape: (5, 137)
ID PREFNAME CITY PREFEC HRDIST Q1 Q2 Q3 Q4 Q5_1 Q5_2 Q5_3 Q6_1 Q6_2 Q6_3 Q7_1 Q7_2 Q7_3 Q7_4 Q7_5 Q7_6 Q8 Q9_1 Q9_2 Q9_3 Q9_4 Q9_5 Q9_6 Q9_7 Q9_8 Q9_9 Q10 Q11_1 Q11_2 Q12 Q13_1 Q13_2 Q23_17 Q24_1 Q24_2 Q24_3 Q24_4 Q24_5 Q24_6 Q24_7 Q25_1 Q25_2 Q25_3 Q25_4 Q25_5 Q26_1 Q26_2_1 Q26_2_2 Q26_2_3 Q26_3_1 Q26_3_2 Q26_3_3 Q27 F1 F2 F3 F4 Q2FA Q4FA Q5FA Q6FA Q8FA Q13FA Q18FA Q19FA Q26_2FA Q26_3FA F3FA F4FA
i64 str str i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 str str str str str str str str str str str str
4 "北海道" "札幌市中央区" 1 1 2 1 4 1 6 2 5 1 6 4 1 2 2 2 3 3 1 1 0 0 0 0 0 0 0 0 3 3 3 4 0 0 4 2 5 3 4 4 4 2 4 3 4 2 3 3 66 66 66 2 6 7 3 2 4 3 1 "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA"
6 "北海道" "札幌市中央区" 1 1 2 4 1 4 6 2 7 1 6 5 5 2 2 5 5 5 4 1 0 0 0 0 0 0 0 0 2 3 4 2 0 0 4 3 2 2 2 2 3 2 2 2 4 2 3 1 2 1 9 66 66 66 2 1 5 2 2 "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA"
7 "北海道" "札幌市中央区" 1 1 1 66 66 66 66 66 66 66 66 66 66 66 66 66 66 66 1 1 0 0 0 0 0 0 0 0 3 2 3 4 0 0 3 3 4 4 3 3 2 2 3 4 2 3 3 3 66 66 66 1 2 3 2 2 3 4 6 "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA"
10 "北海道" "札幌市中央区" 1 1 1 66 66 66 66 66 66 66 66 66 66 66 66 66 66 66 66 0 0 0 0 0 0 0 0 1 3 2 2 4 0 0 3 null null null null null null null 5 4 4 4 4 3 66 66 66 null null null null 2 7 2 6 "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA"
11 "北海道" "札幌市豊平区" 1 3 2 1 2 1 6 5 1 1 3 2 null 2 2 3 3 4 1 1 1 1 0 0 0 0 0 0 2 3 4 2 0 1 3 2 3 4 4 3 3 3 4 4 4 3 3 3 66 66 66 1 2 null 3 2 7 7 6 "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "NA" "大学中退" "NA"

逆に、Windowsで開いたファイルが文字化けする場合はMac/Linuxで作成された可能性が高いです。Mac/LinuxではUTF8というエンコーディングを使っているので、そのように指定すれば文字化けせずに読み込めるはずです。

  • ただし、最近のWindowsではUTF8が使われて、文字化けが起こらないことがあります。
LibreOffice

ところで、エクセルで読み込む際の文字化けを解決することはできません。その場合は無料のオフィスソフトであるLibreOfficeを使うことをおすすめします。

12.4 データの在り処

政治学や周辺領域で利用可能なデータが集まっているサイトを紹介します。