🐡

pythonでcsvを読み込む

2023/03/12に公開

最近Pythonでcsvを読み込み、データを操作することが多くなりました。
そのため、これを機にPythonでcsvを操作できるライブラリはどのようなものがあるか調べることにしました。
本記事ではcsv読み込みに絞って比較したいと思います。

なお、csvデータは気象庁が公開している過去の気象データを使用させて頂いております。
気象庁ホームページ

csvデータを操作するライブラリ

pythonでcsvを操作できる以下のライブラリについて比較します。

  • 標準機能・標準ライブラリ(csvモジュール)
  • NumPy
  • pandas
  • Polars

標準機能・標準ライブラリでcsvを読み込む

ファイルオブジェクトのメソッド

まずは、pythonの標準機能のファイルオブジェクトのreadメソッドでcsvを読み込みます。
7. 入力と出力 — Python ドキュメント

with open("data/sample.csv") as csvfile:
    data = csvfile.read()
    print(data)
    print("-------------")
    print(type(data))

読み込んだdata/sample.csvデータ

東京 東京 東京 東京 東京 東京 東京 東京 東京
年月 平均気温(℃) 平均気温(℃) 平均気温(℃) 平均蒸気圧(hPa) 平均蒸気圧(hPa) 平均蒸気圧(hPa) 平均現地気圧(hPa) 平均現地気圧(hPa) 平均現地気圧(hPa)
品質情報 均質番号 品質情報 均質番号 品質情報 均質番号
1950/9 23.8 8 1 22.9 8 1 0 1
1950/10 15.8 8 1 13.5 8 1 0 1
1950/11 11.1 8 1 9.9 8 1 0 1
1950/12 5.4 8 1 5.9 8 1 0 1
1951/1 3.3 8 1 4.6 8 1 1017.2 8 1
1951/2 4.5 8 1 5.3 8 1 1015.2 8 1
1951/3 8.8 8 1 7.4 8 1 1014.5 8 1
1951/4 13.3 8 1 10.5 8 1 1015.1 8 1
1951/5 18.0 8 1 14.6 8 1 1011.1 8 1
1951/6 21.2 8 1 18.8 8 1 1007.3 8 1
1951/7 24.3 8 1 25.3 8 1 1009.8 8 1
1951/8 26.7 8 1 27.8 8 1 1010.7 8 1

出力結果(ファイルオブジェクトreadを使用)

,東京,東京,東京,東京,東京,東京,東京,東京,東京
年月,平均気温(℃),平均気温(℃),平均気温(℃),平均蒸気圧(hPa),平均蒸気圧(hPa),平均蒸気圧(hPa),平均現地気圧(hPa),平均現地気圧(hPa),平均現地気圧(hPa)
,,品質情報,均質番号,,品質情報,均質番号,,品質情報,均質番号
1950/9,23.8,8,1,22.9,8,1,,0,1
1950/10,15.8,8,1,13.5,8,1,,0,1
1950/11,11.1,8,1,9.9,8,1,,0,1
1950/12,5.4,8,1,5.9,8,1,,0,1
1951/1,3.3,8,1,4.6,8,1,1017.2,8,1
1951/2,4.5,8,1,5.3,8,1,1015.2,8,1
1951/3,8.8,8,1,7.4,8,1,1014.5,8,1
1951/4,13.3,8,1,10.5,8,1,1015.1,8,1
1951/5,18.0,8,1,14.6,8,1,1011.1,8,1
1951/6,21.2,8,1,18.8,8,1,1007.3,8,1
1951/7,24.3,8,1,25.3,8,1,1009.8,8,1
1951/8,26.7,8,1,27.8,8,1,1010.7,8,1

-------------
<class 'str'>

型がstringなので、こちらは使用する機会は少ないかもしれません。

標準ライブラリcsvモジュール:reader

次に、pythonの標準ライブラリcsvモジュールを使用してcsvを読み込みます。
csv --- CSV ファイルの読み書き — Python 3 ドキュメント

import csv

with open("data/sample.csv", newline="") as csvfile:
    reader = csv.reader(csvfile)
    data = [row for row in reader]
    print(data)
    print("-------------")
    print(type(data))

出力結果(csv.readerを使用)

[['', '東京', '東京', '東京', '東京', '東京', '東京', '東京', '東京', '東京'], ['年月', '平均気温(℃)', '平均気温(℃)', '平均気温(℃)', '平均蒸気圧(hPa)', '平均蒸気圧(hPa)', '平均蒸気圧(hPa)', '平均現地気圧(hPa)', '平均現地気圧(hPa)', '平均現地気圧(hPa)'], ['', '', '品質情報', '均質番号', '', '品質情報', '均質番号', '', '品質情報', '均質番号'], ['1950/9', '23.8', '8', '1', '22.9', '8', '1', '', '0', '1'], ['1950/10', '15.8', '8', '1', '13.5', '8', '1', '', '0', '1'], ['1950/11', '11.1', '8', '1', '9.9', '8', '1', '', '0', '1'], ['1950/12', '5.4', '8', '1', '5.9', '8', '1', '', '0', '1'], ['1951/1', '3.3', '8', '1', '4.6', '8', '1', '1017.2', '8', '1'], ['1951/2', '4.5', '8', '1', '5.3', '8', '1', '1015.2', '8', '1'], ['1951/3', '8.8', '8', '1', '7.4', '8', '1', '1014.5', '8', '1'], ['1951/4', '13.3', '8', '1', '10.5', '8', '1', '1015.1', '8', '1'], ['1951/5', '18.0', '8', '1', '14.6', '8', '1', '1011.1', '8', '1'], ['1951/6', '21.2', '8', '1', '18.8', '8', '1', '1007.3', '8', '1'], ['1951/7', '24.3', '8', '1', '25.3', '8', '1', '1009.8', '8', '1'], ['1951/8', '26.7', '8', '1', '27.8', '8', '1', '1010.7', '8', '1']]
-------------
<class 'list'>

読み込んだcsvデータがlist型となりました。

標準ライブラリcsvモジュール:DictReader

辞書型で読み込むこともできます。

import csv

with open('data/sample.csv', newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    data = [row for row in reader]
    print(data)
    print("-------------")
    print(type(data))

しかし、ヘッダーが複数行ある場合は以下のように正しく読み込めませんでした。

出力結果(csv.DictReaderを使用)

[{'': '年月', '東京': '平均現地気圧(hPa)'}, {'': '', '東京': '均質番号'}, {'': '1950/9', '東京': '1'}, {'': '1950/10', '東京': '1'}, {'': '1950/11', '東京': '1'}, {'': '1950/12', '東京': '1'}, {'': '1951/1', '東京': '1'}, {'': '1951/2', '東京': '1'}, {'': '1951/3', '東京': '1'}, {'': '1951/4', '東京': '1'}, {'': '1951/5', '東京': '1'}, {'': '1951/6', '東京': '1'}, {'': '1951/7', '東京': '1'}, {'': '1951/8', '東京': '1'}]
-------------
<class 'list'>

ヘッダーが1行しかなく、列の名称が一意の場合は正しく読み込めました。

import csv

with open('data/sample_2.csv', newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    data = [row for row in reader]
    print(data)
    print("-------------")
    print(type(data))

読み込んだdata/sample_2.csvのデータ

年月 平均気温(℃) 平均蒸気圧(hPa) 平均現地気圧(hPa)
1950/9 23.8 22.9
1950/10 15.8 13.5
1950/11 11.1 9.9
1950/12 5.4 5.9
1951/1 3.3 4.6 1017.2
1951/2 4.5 5.3 1015.2
1951/3 8.8 7.4 1014.5
1951/4 13.3 10.5 1015.1
1951/5 18.0 14.6 1011.1
1951/6 21.2 18.8 1007.3
1951/7 24.3 25.3 1009.8
1951/8 26.7 27.8 1010.7

出力結果

[{'年月': '1950/9', '平均気温(℃)': '23.8', '平均蒸気圧(hPa)': '22.9', '平均現地気圧(hPa)': ''}, {'年月': '1950/10', '平均気温(℃)': '15.8', '平均蒸気圧(hPa)': '13.5', '平均現地気圧(hPa)': ''}, {'年月': '1950/11', '平均気温(℃)': '11.1', '平均蒸気圧(hPa)': '9.9', '平均現地気圧(hPa)': ''}, {'年月': '1950/12', '平均気温(℃)': '5.4', '平均蒸気圧(hPa)': '5.9', '平均現地気圧(hPa)': ''}, {'年月': '1951/1', '平均気温(℃)': '3.3', '平均蒸気圧(hPa)': '4.6', '平均現地気圧(hPa)': '1017.2'}, {'年月': '1951/2', '平均気温(℃)': '4.5', '平均蒸気圧(hPa)': '5.3', '平均現地気圧(hPa)': '1015.2'}, {'年月': '1951/3', '平均気温(℃)': '8.8', '平均蒸気圧(hPa)': '7.4', '平均現地気圧(hPa)': '1014.5'}, {'年月': '1951/4', '平均気温(℃)': '13.3', '平均蒸気圧(hPa)': '10.5', '平均現地気圧(hPa)': '1015.1'}, {'年月': '1951/5', '平均気温(℃)': '18.0', '平均蒸気圧(hPa)': '14.6', '平均現地気圧(hPa)': '1011.1'}, {'年月': '1951/6', '平均気温(℃)': '21.2', '平均蒸気圧(hPa)': '18.8', '平均現地気圧(hPa)': '1007.3'}, {'年月': '1951/7', '平均気温(℃)': '24.3', '平均蒸気圧(hPa)': '25.3', '平均現地気圧(hPa)': '1009.8'}, {'年月': '1951/8', '平均気温(℃)': '26.7', '平均蒸気圧(hPa)': '27.8', '平均現地気圧(hPa)': '1010.7'}]
-------------
<class 'list'>

NumPyでcsv読み込み

NumPyを使用してcsvを読み込みます。

numpy.loadtxt — NumPy Manual

import numpy as np

sample = np.loadtxt("data/sample.csv", delimiter=",", dtype="unicode")
print(sample)
print("-------------")
print(type(sample))

csvファイルの場合、引数:delimiter=","を指定しないとエラーになります。
また、csvデータ内に数字以外の値が存在する場合エラーとなります。
日本語が含まれている場合はdtype="unicode"を指定します。

出力結果(読み込み成功)

[['' '東京' '東京' '東京' '東京' '東京' '東京' '東京' '東京' '東京']
 ['年月' '平均気温(℃)' '平均気温(℃)' '平均気温(℃)' '平均蒸気圧(hPa)' '平均蒸気圧(hPa)'
  '平均蒸気圧(hPa)' '平均現地気圧(hPa)' '平均現地気圧(hPa)' '平均現地気圧(hPa)']
 ['' '' '品質情報' '均質番号' '' '品質情報' '均質番号' '' '品質情報' '均質番号']
 ['1950/9' '23.8' '8' '1' '22.9' '8' '1' '' '0' '1']
 ['1950/10' '15.8' '8' '1' '13.5' '8' '1' '' '0' '1']
 ['1950/11' '11.1' '8' '1' '9.9' '8' '1' '' '0' '1']
 ['1950/12' '5.4' '8' '1' '5.9' '8' '1' '' '0' '1']
 ['1951/1' '3.3' '8' '1' '4.6' '8' '1' '1017.2' '8' '1']
 ['1951/2' '4.5' '8' '1' '5.3' '8' '1' '1015.2' '8' '1']
 ['1951/3' '8.8' '8' '1' '7.4' '8' '1' '1014.5' '8' '1']
 ['1951/4' '13.3' '8' '1' '10.5' '8' '1' '1015.1' '8' '1']
 ['1951/5' '18.0' '8' '1' '14.6' '8' '1' '1011.1' '8' '1']
 ['1951/6' '21.2' '8' '1' '18.8' '8' '1' '1007.3' '8' '1']
 ['1951/7' '24.3' '8' '1' '25.3' '8' '1' '1009.8' '8' '1']
 ['1951/8' '26.7' '8' '1' '27.8' '8' '1' '1010.7' '8' '1']]
-------------
<class 'numpy.ndarray'>

読み込み失敗(delimiter,dtype指定なし)

import numpy as np

sample = np.loadtxt("data/sample.csv")
print(sample)
print("-------------")
print(type(sample))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
ValueError: could not convert string to float: ','

The above exception was the direct cause of the following exception:

ValueError                                Traceback (most recent call last)
Cell In[8], line 3
      1 import numpy as np
----> 3 sample = np.loadtxt("data/sample.csv")
      4 print(sample)
      5 print("-------------")

ValueError: could not convert string ',東京,東京,東京,東京,東京,東京,東京,東京,東京' to float64 at row 0, column 1.

読み込み失敗(dtype指定なし)

import numpy as np

sample = np.loadtxt("data/sample.csv", delimiter=",")
print(sample)
print("-------------")
print(type(sample))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[9], line 3
      1 import numpy as np
----> 3 sample = np.loadtxt("data/sample.csv", delimiter=",")
      4 print(sample)
      5 print("-------------")

ValueError: could not convert string '' to float64 at row 0, column 1.

pandasでcsv読み込み

pandasでcsvを読み込みます。
pandas.read_csv — pandas documentation

import pandas as pd

df = pd.read_csv('data/sample.csv')
print(df)
print("-------------")
print(type(df))

pandasで読み込んだdata/sample.csvデータ

   Unnamed: 0       東京     東京.1     東京.2        東京.3        東京.4        東京.5  \
0          年月  平均気温(℃)  平均気温(℃)  平均気温(℃)  平均蒸気圧(hPa)  平均蒸気圧(hPa)  平均蒸気圧(hPa)   
1         NaN      NaN     品質情報     均質番号         NaN        品質情報        均質番号   
2      1950/9     23.8        8        1        22.9           8           1   
3     1950/10     15.8        8        1        13.5           8           1   
4     1950/11     11.1        8        1         9.9           8           1   
5     1950/12      5.4        8        1         5.9           8           1   
6      1951/1      3.3        8        1         4.6           8           1   
7      1951/2      4.5        8        1         5.3           8           1   
8      1951/3      8.8        8        1         7.4           8           1   
9      1951/4     13.3        8        1        10.5           8           1   
10     1951/5     18.0        8        1        14.6           8           1   
11     1951/6     21.2        8        1        18.8           8           1   
12     1951/7     24.3        8        1        25.3           8           1   
13     1951/8     26.7        8        1        27.8           8           1   

           東京.6         東京.7         東京.8  
0   平均現地気圧(hPa)  平均現地気圧(hPa)  平均現地気圧(hPa)  
1           NaN         品質情報         均質番号  
2           NaN            0            1  
3           NaN            0            1  
4           NaN            0            1  
5           NaN            0            1  
6        1017.2            8            1  
7        1015.2            8            1  
8        1014.5            8            1  
9        1015.1            8            1  
10       1011.1            8            1  
11       1007.3            8            1  
12       1009.8            8            1  
13       1010.7            8            1  
-------------
<class 'pandas.core.frame.DataFrame'>

行ラベル、列名を指定していない場合、自動で1行目がcolumn、2行目からindexは0から連番で振られます。
空白セル(None)はNaN(欠損値)と表示されます。

以下のようにindex_colに列名や列番号を指定したり、headerに列名の行を指定することもできます。

import pandas as pd

df = pd.read_csv('data/sample.csv', index_col=0, header=[0,1,2])
print(df)
print("-------------")
print(type(df))

pandas:index_col,headerを指定して読み込み

                        東京                                         \
年月                 平均気温(℃)                   平均蒸気圧(hPa)             
        Unnamed: 1_level_2 品質情報 均質番号 Unnamed: 4_level_2 品質情報 均質番号   
1950/9                23.8    8    1               22.9    8    1   
1950/10               15.8    8    1               13.5    8    1   
1950/11               11.1    8    1                9.9    8    1   
1950/12                5.4    8    1                5.9    8    1   
1951/1                 3.3    8    1                4.6    8    1   
1951/2                 4.5    8    1                5.3    8    1   
1951/3                 8.8    8    1                7.4    8    1   
1951/4                13.3    8    1               10.5    8    1   
1951/5                18.0    8    1               14.6    8    1   
1951/6                21.2    8    1               18.8    8    1   
1951/7                24.3    8    1               25.3    8    1   
1951/8                26.7    8    1               27.8    8    1   

                                      
年月             平均現地気圧(hPa)            
        Unnamed: 7_level_2 品質情報 均質番号  
1950/9                 NaN    0    1  
1950/10                NaN    0    1  
1950/11                NaN    0    1  
1950/12                NaN    0    1  
1951/1              1017.2    8    1  
1951/2              1015.2    8    1  
1951/3              1014.5    8    1  
1951/4              1015.1    8    1  
1951/5              1011.1    8    1  
1951/6              1007.3    8    1  
1951/7              1009.8    8    1  
1951/8              1010.7    8    1  
-------------
<class 'pandas.core.frame.DataFrame'>

以下のように列名を別名で指定してcsvを読み込むことも可能です。

import pandas as pd

df = pd.read_csv(
    "data/sample.csv",
    names=[
        "年月",
        "平均気温(℃)",
        "平均気温(℃)_品質情報",
        "平均気温(℃)_均質番号",
        "平均蒸気圧(hPa)",
        "平均蒸気圧(hPa)_品質情報",
        "平均蒸気圧(hPa)_均質番号",
        "平均現地気圧(hPa)",
        "平均現地気圧(hPa)_品質情報",
        "平均現地気圧(hPa)_均質番号",
    ],
    index_col=0,
    skiprows=3,
)
print(df)
print("-------------")
print(type(df))

pandas:列名を指定して読み込み

         平均気温(℃)  平均気温(℃)_品質情報  平均気温(℃)_均質番号  平均蒸気圧(hPa)  平均蒸気圧(hPa)_品質情報  \
年月                                                                          
1950/9      23.8             8             1        22.9                8   
1950/10     15.8             8             1        13.5                8   
1950/11     11.1             8             1         9.9                8   
1950/12      5.4             8             1         5.9                8   
1951/1       3.3             8             1         4.6                8   
1951/2       4.5             8             1         5.3                8   
1951/3       8.8             8             1         7.4                8   
1951/4      13.3             8             1        10.5                8   
1951/5      18.0             8             1        14.6                8   
1951/6      21.2             8             1        18.8                8   
1951/7      24.3             8             1        25.3                8   
1951/8      26.7             8             1        27.8                8   

         平均蒸気圧(hPa)_均質番号  平均現地気圧(hPa)  平均現地気圧(hPa)_品質情報  平均現地気圧(hPa)_均質番号  
年月                                                                         
1950/9                 1          NaN                 0                 1  
1950/10                1          NaN                 0                 1  
1950/11                1          NaN                 0                 1  
1950/12                1          NaN                 0                 1  
1951/1                 1       1017.2                 8                 1  
1951/2                 1       1015.2                 8                 1  
1951/3                 1       1014.5                 8                 1  
1951/4                 1       1015.1                 8                 1  
1951/5                 1       1011.1                 8                 1  
1951/6                 1       1007.3                 8                 1  
1951/7                 1       1009.8                 8                 1  
1951/8                 1       1010.7                 8                 1  
-------------
<class 'pandas.core.frame.DataFrame'>

Polarsでcsv読み込み

Polarsでcsvを読み込みます。

polars.read_csv — Polars documentation

import polars as pl

df = pl.read_csv('data/sample.csv')
print(df)
print("-------------")
print(type(df))

polarsで読み込んだdata/sample.csvデータ

shape: (14, 10)
┌─────────┬────┬────────────┬────────────┬─────┬────────────┬────────────┬────────────┬────────────┐
│         ┆ 東 ┆ 東京_dupli ┆ 東京_dupli ┆ ... ┆ 東京_dupli ┆ 東京_dupli ┆ 東京_dupli ┆ 東京_dupli │
│ ---     ┆ 京 ┆ cated_0    ┆ cated_1    ┆     ┆ cated_4    ┆ cated_5    ┆ cated_6    ┆ cated_7    │
│ str     ┆ -- ┆ ---        ┆ ---        ┆     ┆ ---        ┆ ---        ┆ ---        ┆ ---        │
│         ┆ -  ┆ str        ┆ str        ┆     ┆ str        ┆ str        ┆ str        ┆ str        │
│         ┆ st ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│         ┆ r  ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
╞═════════╪════╪════════════╪════════════╪═════╪════════════╪════════════╪════════════╪════════════╡
│ 年月    ┆ 平 ┆ 平均気温(℃ ┆ 平均気温(℃ ┆ ... ┆ 平均蒸気圧 ┆ 平均現地気 ┆ 平均現地気 ┆ 平均現地気 │
│         ┆ 均 ┆ )          ┆ )          ┆     ┆ (hPa)      ┆ 圧(hPa)    ┆ 圧(hPa)    ┆ 圧(hPa)    │
│         ┆ 気 ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│         ┆ 温 ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│         ┆ (℃ ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│         ┆ )  ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│ null    ┆ nu ┆ 品質情報   ┆ 均質番号   ┆ ... ┆ 均質番号   ┆ null       ┆ 品質情報   ┆ 均質番号   │
│         ┆ ll ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│ 1950/9  ┆ 23 ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│         ┆ .8 ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│ 1950/10 ┆ 15 ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│         ┆ .8 ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│ ...     ┆ .. ┆ ...        ┆ ...        ┆ ... ┆ ...        ┆ ...        ┆ ...        ┆ ...        │
│         ┆ .  ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│ 1951/5  ┆ 18 ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1011.1     ┆ 8          ┆ 1          │
│         ┆ .0 ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│ 1951/6  ┆ 21 ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1007.3     ┆ 8          ┆ 1          │
│         ┆ .2 ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│ 1951/7  ┆ 24 ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1009.8     ┆ 8          ┆ 1          │
│         ┆ .3 ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
│ 1951/8  ┆ 26 ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1010.7     ┆ 8          ┆ 1          │
│         ┆ .7 ┆            ┆            ┆     ┆            ┆            ┆            ┆            │
└─────────┴────┴────────────┴────────────┴─────┴────────────┴────────────┴────────────┴────────────┘
-------------
<class 'polars.internals.dataframe.frame.DataFrame'>

polarsの場合、空白セル(None)はnullと表示されます。

Process missing data - Polars - User Guide

skip_rowsを指定することで、指定した行数の次の行から読み込みます。

import polars as pl

df = pl.read_csv('data/sample.csv', skip_rows=2)
print(df)
print("-------------")
print(type(df))

polars:skip_rowsを指定して読み込み

shape: (12, 10)
┌─────────┬────────────┬────────────┬────────────┬─────┬────────────┬────────────┬────────────┬────────────┐
│         ┆ _duplicate ┆ 品質情報   ┆ 均質番号   ┆ ... ┆ 均質番号_d ┆ _duplicate ┆ 品質情報_d ┆ 均質番号_d │
│ ---     ┆ d_0        ┆ ---        ┆ ---        ┆     ┆ uplicated_ ┆ d_2        ┆ uplicated_ ┆ uplicated_ │
│ str     ┆ ---        ┆ i64        ┆ i64        ┆     ┆ 0          ┆ ---        ┆ 1          ┆ 1          │
│         ┆ f64        ┆            ┆            ┆     ┆ ---        ┆ f64        ┆ ---        ┆ ---        │
│         ┆            ┆            ┆            ┆     ┆ i64        ┆            ┆ i64        ┆ i64        │
╞═════════╪════════════╪════════════╪════════════╪═════╪════════════╪════════════╪════════════╪════════════╡
│ 1950/9  ┆ 23.8       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│ 1950/10 ┆ 15.8       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│ 1950/11 ┆ 11.1       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│ 1950/12 ┆ 5.4        ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│ ...     ┆ ...        ┆ ...        ┆ ...        ┆ ... ┆ ...        ┆ ...        ┆ ...        ┆ ...        │
│ 1951/5  ┆ 18.0       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1011.1     ┆ 8          ┆ 1          │
│ 1951/6  ┆ 21.2       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1007.3     ┆ 8          ┆ 1          │
│ 1951/7  ┆ 24.3       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1009.8     ┆ 8          ┆ 1          │
│ 1951/8  ┆ 26.7       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1010.7     ┆ 8          ┆ 1          │
└─────────┴────────────┴────────────┴────────────┴─────┴────────────┴────────────┴────────────┴────────────┘
-------------
<class 'polars.internals.dataframe.frame.DataFrame'>

polarsは2行以上のヘッダーを指定できないようです。
has_header=Falseと指定すると、すべての行がデータとして読み込まれ、列名はcolumn_x(xは1から連番)という名称が自動で生成されます。

import polars as pl

df = pl.read_csv('data/sample.csv', has_header=False)
print(df)
print("-------------")
print(type(df))

polars:has_header=Falseを指定して読み込み

shape: (15, 10)
┌──────────┬───────────┬───────────┬───────────┬─────┬───────────┬───────────┬───────────┬─────────┐
│ column_1 ┆ column_2  ┆ column_3  ┆ column_4  ┆ ... ┆ column_7  ┆ column_8  ┆ column_9  ┆ column_ │
│ ---      ┆ ---       ┆ ---       ┆ ---       ┆     ┆ ---       ┆ ---       ┆ ---       ┆ 10      │
│ str      ┆ str       ┆ str       ┆ str       ┆     ┆ str       ┆ str       ┆ str       ┆ ---     │
│          ┆           ┆           ┆           ┆     ┆           ┆           ┆           ┆ str     │
╞══════════╪═══════════╪═══════════╪═══════════╪═════╪═══════════╪═══════════╪═══════════╪═════════╡
│ null     ┆ 東京      ┆ 東京      ┆ 東京      ┆ ... ┆ 東京      ┆ 東京      ┆ 東京      ┆ 東京    │
│ 年月     ┆ 平均気温( ┆ 平均気温( ┆ 平均気温( ┆ ... ┆ 平均蒸気  ┆ 平均現地  ┆ 平均現地  ┆ 平均現  │
│          ┆ ℃)        ┆ ℃)        ┆ ℃)        ┆     ┆ 圧(hPa)   ┆ 気圧(hPa) ┆ 気圧(hPa) ┆ 地気圧( │
│          ┆           ┆           ┆           ┆     ┆           ┆           ┆           ┆ hPa)    │
│ null     ┆ null      ┆ 品質情報  ┆ 均質番号  ┆ ... ┆ 均質番号  ┆ null      ┆ 品質情報  ┆ 均質番  │
│          ┆           ┆           ┆           ┆     ┆           ┆           ┆           ┆ 号      │
│ 1950/9   ┆ 23.8      ┆ 8         ┆ 1         ┆ ... ┆ 1         ┆ null      ┆ 0         ┆ 1       │
│ ...      ┆ ...       ┆ ...       ┆ ...       ┆ ... ┆ ...       ┆ ...       ┆ ...       ┆ ...     │
│ 1951/5   ┆ 18.0      ┆ 8         ┆ 1         ┆ ... ┆ 1         ┆ 1011.1    ┆ 8         ┆ 1       │
│ 1951/6   ┆ 21.2      ┆ 8         ┆ 1         ┆ ... ┆ 1         ┆ 1007.3    ┆ 8         ┆ 1       │
│ 1951/7   ┆ 24.3      ┆ 8         ┆ 1         ┆ ... ┆ 1         ┆ 1009.8    ┆ 8         ┆ 1       │
│ 1951/8   ┆ 26.7      ┆ 8         ┆ 1         ┆ ... ┆ 1         ┆ 1010.7    ┆ 8         ┆ 1       │
└──────────┴───────────┴───────────┴───────────┴─────┴───────────┴───────────┴───────────┴─────────┘
-------------
<class 'polars.internals.dataframe.frame.DataFrame'>

polarsも以下のように列名を別名で指定してcsvを読み込むことも可能です。

import polars as pl

df = pl.read_csv(
    "data/sample.csv",
    skip_rows=2,
    new_columns=[
        "年月",
        "平均気温(℃)",
        "平均気温(℃)_品質情報",
        "平均気温(℃)_均質番号",
        "平均蒸気圧(hPa)",
        "平均蒸気圧(hPa)_品質情報",
        "平均蒸気圧(hPa)_均質番号",
        "平均現地気圧(hPa)",
        "平均現地気圧(hPa)_品質情報",
        "平均現地気圧(hPa)_均質番号",
    ]
)
print(df)
print("-------------")
print(type(df))

polars:new_columnsを指定して読み込み

shape: (12, 10)
┌─────────┬────────────┬────────────┬────────────┬─────┬────────────┬────────────┬────────────┬────────────┐
│ 年月    ┆ 平均気温(℃ ┆ 平均気温(℃ ┆ 平均気温(℃ ┆ ... ┆ 平均蒸気圧 ┆ 平均現地気 ┆ 平均現地気 ┆ 平均現地気 │
│ ---     ┆ )          ┆ )_品質情報 ┆ )_均質番号 ┆     ┆ (hPa)_均質 ┆ 圧(hPa)    ┆ 圧(hPa)_品 ┆ 圧(hPa)_均 │
│ str     ┆ ---        ┆ ---        ┆ ---        ┆     ┆ 番号       ┆ ---        ┆ 質情報     ┆ 質番号     │
│         ┆ f64        ┆ i64        ┆ i64        ┆     ┆ ---        ┆ f64        ┆ ---        ┆ ---        │
│         ┆            ┆            ┆            ┆     ┆ i64        ┆            ┆ i64        ┆ i64        │
╞═════════╪════════════╪════════════╪════════════╪═════╪════════════╪════════════╪════════════╪════════════╡
│ 1950/9  ┆ 23.8       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│ 1950/10 ┆ 15.8       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│ 1950/11 ┆ 11.1       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│ 1950/12 ┆ 5.4        ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ null       ┆ 0          ┆ 1          │
│ ...     ┆ ...        ┆ ...        ┆ ...        ┆ ... ┆ ...        ┆ ...        ┆ ...        ┆ ...        │
│ 1951/5  ┆ 18.0       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1011.1     ┆ 8          ┆ 1          │
│ 1951/6  ┆ 21.2       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1007.3     ┆ 8          ┆ 1          │
│ 1951/7  ┆ 24.3       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1009.8     ┆ 8          ┆ 1          │
│ 1951/8  ┆ 26.7       ┆ 8          ┆ 1          ┆ ... ┆ 1          ┆ 1010.7     ┆ 8          ┆ 1          │
└─────────┴────────────┴────────────┴────────────┴─────┴────────────┴────────────┴────────────┴────────────┘
-------------
<class 'polars.internals.dataframe.frame.DataFrame'>

まとめ

個人的感想

今回はpythonでcsvを読み込みについて記載しました。
単純なcsvを読み込むだけの場合は、標準ライブラリの使用で問題なさそうです。
しかし、csvを読み込んでデータを操作・編集したい場合は処理が複雑になりそうなので、NumPy, pandasやpolarsを使用したほうが効率がよさそうに感じました。

NumPy,pandas,polarsはcsv読み込み処理については大きな違いはありませんでした。
そのため、csvを読み込んだデータの型によって使い方が変わってくると思います。
以下にデータ型をまとめます。

各ライブラリと型の比較表

ライブラリのメソッド csv読み込み後のデータの型
ファイルオブジェクトread string
csv.reader list
csv.DictReader [dict]
numpy.loadtxt numpy.ndarray
pandas.read_csv pandas.core.frame.DataFrame
polars.read_csv polars.internals.dataframe.frame.DataFrame

他の処理について別の機会にまとめようと思います。

Discussion