▲CSVファイルの入出力¶
CSVファイルの入出力について説明します。
参考
CSV形式とは¶
CSV形式とは "comma-separated values" の略で、 複数の値をコンマで区切って記録するファイル形式です。
みなさんExcelを使ったことがあると思いますが、 Excelでは1つのセルに1つの値(数値や文字など)が入っていて、 その他のセルの値とは独立に扱えますよね。
それと同じように、CSV形式では、,
(コンマ)で区切られた要素はそれぞれ独立の値として扱われます。
たとえばサークルのメンバーデータを作ることを考えましょう。 メンバーは「鈴木一郎」と「山田花子」の2名で、 それぞれ『氏名』『ニックネーム』『出身地』を記録しておきたいと思います。
表で表すとこんなデータです。
ID |
氏名 |
ニックネーム |
出身地 |
---|---|---|---|
user1 |
鈴木一郎 |
イチロー |
広島 |
user2 |
山田花子 |
はなこ |
名古屋 |
これをCSV形式で表すと次のようになります。
'user1','鈴木一郎','イチロー','広島' 'user2','山田花子','はなこ','名古屋'CSVファイルの読み込み¶
CSVファイルを読み書きするには、 ファイルをオープンして、そのファイルオブジェクトから、 CSVリーダを作ります。
CSVリーダとは、CSVファイルからデータを読み込むためのオブジェクトで、 このオブジェクトのメソッドを呼び出すことにより、CSVファイルからデータを読み込むことができます。
CSVリーダを作るには、 csv
というモジュールの csv.reader
という関数にファイルオブジェクトを渡します。
たとえば、次のような表で表されるCSVファイル small.csv
を読み込んでみましょう。
0列目 | 1列目 | 2列目 | 3列目 | 4列目
11 | 12 | 13 | 14 | 15 21 | 22 | 23 | 24 | 25 31 | 32 | 33 | 34 | 35
[1]:
import csv
f = open('small.csv', 'r')
dataReader = csv.reader(f)
このオブジェクトもイテレータで、next
という関数を呼び出すことができます。
[2]:
next(dataReader)
[2]:
['11', '12', '13', '14', '15']
このようにして CSVファイルを読むと、 CSVファイルの各行のデータが文字列のリストとなって返されます。
[3]:
next(dataReader)
[3]:
['21', '22', '23', '24', '25']
[4]:
row = next(dataReader)
[5]:
row
[5]:
['31', '32', '33', '34', '35']
[6]:
row[2]
[6]:
'33'
数値が ''
で囲われている場合、数値ではなく文字列として扱われているので、そのまま計算に使用することができません。
文字列が整数を表す場合、int
関数によって文字列を整数に変換することができます。 文字列が小数を含む場合は float
関数で浮動小数点数型に変換、文字列が複素数を表す場合は complex
関数で複素数に変換します。
[7]:
int(row[2])
[7]:
33
ファイルの終わりまで達した後に next
関数を実行すると、下のようにエラーが返ってきます。
[8]:
next(dataReader)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
Cell In[8], line 1
----> 1 next(dataReader)
StopIteration:
ファイルを使い終わったらクローズすることを忘れないようにしましょう。
[9]:
f.close()
CSVファイルに対するfor文¶
CSVリーダもイテレータですので、for文の in
の後に書くことができます。
for row in dataReader:
...
繰り返しの各ステップで、next(dataReader)
が呼び出されて、 row
にその値が設定され、for文の中身が実行されます。
[10]:
f = open('small.csv', 'r')
dataReader = csv.reader(f)
for row in dataReader:
print(row)
f.close()
['11', '12', '13', '14', '15']
['21', '22', '23', '24', '25']
['31', '32', '33', '34', '35']
CSVファイルに対するwith文¶
以下はwith文を使った例です。
[11]:
with open('small.csv', 'r') as f:
dataReader = csv.reader(f)
for row in dataReader:
print(row)
['11', '12', '13', '14', '15']
['21', '22', '23', '24', '25']
['31', '32', '33', '34', '35']
CSVファイルの書き込み¶
CSVファイルを作成して書き込むには、CSVライターを作ります。
CSVライターとは、CSVファイルを作ってデータを書き込むためのオブジェクトで、 このオブジェクトのメソッドを呼び出すことにより、データがCSV形式でファイルに書き込まれます。
CSVライターを作るには、 csv
というモジュールの csv.writer
という関数にファイルオブジェクトを渡します。 ここで、半角英数文字以外の文字(たとえば日本語文字や全角英数文字)を書き込み・書き出しする際には、 文字コード(たとえば encoding='utf-8'
)を指定し、 また書き出しの際にはさらに改行コードとして newline=''
を指定しないと文字化けが生じる可能性があります。
[12]:
f = open('out.csv', 'w', encoding='utf-8', newline='')
[13]:
dataWriter = csv.writer(f)
[14]:
dir(dataWriter)
[14]:
['__class__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'dialect',
'writerow',
'writerows']
[15]:
dataWriter.writerow([1,2,3])
[15]:
7
[16]:
dataWriter.writerow([21,22,23])
[16]:
10
書き込みモードの場合も、ファイルを使い終わったらクローズすることを忘れないようにしましょう。
[17]:
f.close()
読み込みのときと同様、with文を使うこともできます。
[18]:
with open('out.csv', 'w', encoding='utf-8', newline='') as f:
dataWriter = csv.writer(f)
dataWriter.writerow([1,2,3])
dataWriter.writerow([21,22,23])
東京の7月の気温¶
tokyo-temps.csv
には、気象庁のオープンデータからダウンロードした、 東京の7月の平均気温のデータが入っています。
http://www.data.jma.go.jp/gmd/risk/obsdl/
48行目の第2列に1875年7月の平均気温が入っており、 以下、2016年まで、12行ごとに7月の平均気温が入っています。
以下は、これを取り出すPythonの簡単なコードです。
[19]:
import csv
with open('tokyo-temps.csv', 'r', encoding='shift_jis') as f:
dataReader = csv.reader(f) # csvリーダを作成
n=0
year = 1875
years = []
july_temps = []
for row in dataReader: # CSVファイルの中身を1行ずつ読み込み
n = n+1
if n>=48 and (n-48)%12 == 0: # 48行目からはじめて12か月ごとにif内を実行
years.append(year)
july_temps.append(float(row[1]))
year = year + 1
ファイルをオープンするときに、キーワード引数の encoding
が指定されています。 このファイルはShift_JISという文字コードで書かれているため、 この引数で、ファイルの符号(文字コード)を指定します。 'shift_jis'
はShift_JISを意味します。この他に、'utf-8'
(UTF-8、すなわちビットのUnicode)があります。
変数 years
に年の配列、変数 july_temps
に対応する年の7月の平均気温の配列が設定されます。
[20]:
years
[20]:
[1875,
1876,
1877,
1878,
1879,
1880,
1881,
1882,
1883,
1884,
1885,
1886,
1887,
1888,
1889,
1890,
1891,
1892,
1893,
1894,
1895,
1896,
1897,
1898,
1899,
1900,
1901,
1902,
1903,
1904,
1905,
1906,
1907,
1908,
1909,
1910,
1911,
1912,
1913,
1914,
1915,
1916,
1917,
1918,
1919,
1920,
1921,
1922,
1923,
1924,
1925,
1926,
1927,
1928,
1929,
1930,
1931,
1932,
1933,
1934,
1935,
1936,
1937,
1938,
1939,
1940,
1941,
1942,
1943,
1944,
1945,
1946,
1947,
1948,
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,
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]
[21]:
july_temps
[21]:
[26.0,
24.3,
26.5,
26.0,
26.1,
24.2,
24.0,
24.2,
23.7,
23.4,
23.1,
25.0,
23.6,
24.5,
23.4,
23.5,
24.9,
25.7,
25.3,
26.8,
22.1,
24.1,
22.9,
25.9,
23.2,
22.8,
22.1,
21.8,
23.2,
24.8,
23.3,
23.5,
22.7,
22.1,
24.3,
23.0,
24.5,
24.3,
23.3,
25.5,
24.2,
23.9,
25.7,
26.0,
23.6,
26.1,
24.3,
25.0,
24.0,
26.1,
23.2,
24.6,
26.0,
23.4,
25.9,
26.3,
21.8,
25.7,
26.6,
23.9,
24.3,
24.9,
26.3,
25.0,
26.5,
26.9,
23.7,
27.5,
25.1,
25.6,
22.0,
26.2,
25.7,
26.0,
25.3,
26.5,
24.3,
24.3,
24.7,
22.3,
27.6,
24.2,
24.4,
24.9,
26.1,
25.8,
27.4,
25.1,
25.7,
25.5,
24.2,
24.4,
26.3,
24.7,
25.0,
25.4,
25.8,
25.2,
26.1,
23.4,
25.6,
23.9,
25.8,
27.8,
25.2,
23.8,
26.3,
23.1,
23.8,
26.2,
26.3,
23.9,
27.0,
22.4,
24.1,
25.7,
26.7,
25.5,
22.5,
28.3,
26.4,
26.2,
26.6,
25.3,
25.9,
27.7,
28.5,
28.0,
22.8,
28.5,
25.6,
25.6,
24.4,
27.0,
26.3,
28.0,
27.3,
26.4,
27.3,
26.8,
26.2,
25.4]
ここでは詳しく説明しませんが、線形回帰によるフィッティングを行ってみましょう。
[22]:
import numpy
import matplotlib.pyplot as plt
%matplotlib inline
fitp = numpy.poly1d(numpy.polyfit(years, july_temps, 1))
ma = max(years)
mi = min(years)
xp = numpy.linspace(mi, ma, (ma - mi))
[23]:
plt.plot(years, july_temps, '.', xp, fitp(xp), '-')
plt.show()
練習¶
tokyo-temps.csv
を読み込んで、各行が西暦年と7月の気温のみからなる'tokyo-july-temps.csv'
という名前のCSVファイルを作成してください。 西暦年は1875から2016までとします。作成したCSVファイルをExcelで読み込むとどうなるか確認してください。
[ ]:
以下のセルによってテストしてください。(years
と july_temps
の値がそのままと仮定しています。)
[24]:
with open('tokyo-july-temps.csv', 'r', encoding='shift_jis') as f:
i = 0
dataReader = csv.reader(f)
for row in dataReader:
if int(row[0]) != years[i] or abs(float(row[1])-july_temps[i])>0.000001:
print('error', int(row[0]), float(row[1]))
i += 1
print(i== 142) # 1875年から2016年まで142年間分のデータがあるはずです
True
練習¶
整数データのみからなるCSVファイルの名前を受け取ると、そのCSVファイルの各行を読み込んで整数のリストを作り、 ファイル全体の内容を、そのようなリストのリストとして返す関数 csv_matrix(name)
を定義してください。
たとえば上で用いた small.csv
には次のようなデータが入っています。
0列目 | 1列目 | 2列目 | 3列目 | 4列目
11 | 12 | 13 | 14 | 15 21 | 22 | 23 | 24 | 25 31 | 32 | 33 | 34 | 35
この small.csv
の名前が引数として与えられた場合、
[[11, 12, 13, 14, 15], [21, 22, 23, 24, 25], [31, 32, 33, 34, 35]]
というリストを返します。
[25]:
def csv_matrix(name):
...
以下のセルによってテストしてください。
[26]:
print(csv_matrix('small.csv') == [[11, 12, 13, 14, 15], [21, 22, 23, 24, 25], [31, 32, 33, 34, 35]])
False
練習の解答¶
[27]:
with open('tokyo-july-temps.csv', 'w', encoding='utf-8', newline='') as f:
i = 0
dataWriter = csv.writer(f)
for i in range(len(years)):
dataWriter.writerow([years[i],july_temps[i]])
[28]:
def csv_matrix(name):
rows = []
with open(name, 'r') as f:
dataReader = csv.reader(f)
for row in dataReader:
rows.append([int(x) for x in row])
return rows
[ ]: