質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

1480閲覧

PythonでMultiIndexのDataFrameをスライスで切り出したい

maztips

総合スコア2

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2021/08/05 06:19

前提・実現したいこと

Pythonを使用して、あるNetCDFファイルをXarray.DataArrayで読み込み、さらにPandas.DataFrameに変換したところ、下記のMultiIndexのDataFrameとなりました。
precipitation
lat lon time
89.95 -179.95 2001-01-01 0.0
2001-01-02 0.0
2001-01-03 0.0
2001-01-04 0.0
2001-01-05 0.0
...
-89.95 179.95 2001-01-27 0.0
2001-01-28 0.0
2001-01-29 0.0
2001-01-30 0.0
2001-01-31 0.0

このDataFrameから'lat'インデックスが10.25から12.25まで、'lon'インデックスが105.45から109.25までの部分のみを切り出し、CSVファイルに出力したいです。

発生している問題・エラーメッセージ

TypeError: Cannot cast array data from dtype('float64') to dtype('<U32') according to the rule 'safe'

該当のソースコード

df = df.loc[pd.IndexSlice['{lat_end}':'{lat_start}', '{lon_start}':'{lon_end}', :], :]

Python

1import xarray as xr 2import pandas as pd 3 4# 開始年と終了年の設定 5year_start = 2001 6year_end = 2007 7 8# データ範囲の設定 9lat_start = 10.25 10lat_end = 12.25 11lon_start = 105.45 12lon_end = 109.25 13 14for year in range(year_start, year_end+1): 15 for month in range(1,13): 16 # netcdfファイルをxarray.DataArrayで読み込み 17 file = f'./Precipitation/MSWEP/mswep_SGDN_daily_nc/{year}{month:02}.nc' 18 nc = xr.open_dataset(file) 19 20 # xarray.DataArrayをPandas.DataFrameに変換 21 df = nc.to_dataframe() 22 23 # インデックス'lat'を昇順でソート 24 df = df.sort_index(level='lat') 25 26 # スライスで指定 27 df = df.loc[pd.IndexSlice['{lat_end}':'{lat_start}', '{lon_start}':'{lon_end}', :], :] 28 29 # csvファイルに出力 30 file = f'./Precipitation/MSWEP/mswep_SGDN_daily_csv/{year}{month:02}.csv' 31 df.to_csv(file)

試したこと

pd.locの代わりにpd.xsを使用したり、pd.IndexSliceの代わりにsliceを使用したりしましたが、同じエラーメッセージが発生しました。

補足情報(FW/ツールのバージョンなど)

Python 3.8.3
Pandas 1.0.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

文字列にするとか難しいことは考えず、下記のように書けばできないでしょうか?

python

1df = df.loc[pd.IndexSlice[lat_end:lat_start, lon_start:lon_end, :], :]

投稿2021/08/05 08:57

bsdfan

総合スコア4794

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maztips

2021/08/05 09:44

インデックスの値を文字列と思い込んでいました。回答いただいた表記で質問のエラーは解決しました。ありがとうございます。 ただ、コード中の同じ行で別のエラーが発生してしまいました。(UnsortedIndexError: 'MultiIndex slicing requires the index to be lexsorted: slicing on levels [0, 1], lexsort depth 0') ほかの方の回答で、求めていたデータ自体は得ることができましたが、もしお分かりのことがあればご教示いただけると幸いです。
bsdfan

2021/08/05 09:52

今のプログラムだと、latについてしかソートしていないので、lonについてもソートしないといけないのではないかと df = df.sort_index(level=['lat', 'lon'])
bsdfan

2021/08/05 09:57

ソートが不要で、データを抜き出したいだけなら、ppaulさんの回答のように reset_index してしまうほうが簡単かもしれません。
guest

0

ベストアンサー

条件を満たす緯度と経度を取り出すのは以下のようにやればできます。

python

1>>> print(df) 2 precipitation 3lat lon time 4 89.95 -179.95 2001-01-01 0.0 5 2001-01-02 0.0 6 2001-01-03 0.0 7 10.20 105.50 2001-01-04 0.0 8 10.25 105.45 2002-01-04 0.0 9 12.25 107.25 2003-09-05 0.0 10 111.25 2004-01-05 0.0 11-89.95 179.95 2001-01-27 0.0 12 2001-01-28 0.0 13 2001-01-29 0.0 14 2001-01-30 0.0 15 2001-01-31 0.0 16>>> df2 = df.reset_index() 17>>> df3 = df2[(df2['lat'] >= 10.25) & (df2['lat'] <= 12.25) & (df2['lon'] >= 105.45) & (df2['lat'] <= 109.25)] 18>>> print(df3) 19 lat lon time precipitation 204 10.25 105.45 2002-01-04 0.0 215 12.25 107.25 2003-09-05 0.0 226 12.25 111.25 2004-01-05 0.0

年ごと、月ごとに分けるのは、以下のようにします。

python

1>>> df4 = df3[(df3['time'].dt.year == 2002) & (df3['time'].dt.month == 1)] 2>>> print(df4) 3 lat lon time precipitation 44 10.25 105.45 2002-01-04 0.0

これを参考にしてやってみてください。

投稿2021/08/05 07:22

ppaul

総合スコア24670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maztips

2021/08/05 09:47

そのような取り出し方法があったのですね。上記の通りのコードで、無事求めていたデータを得ることができました。大変勉強になりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問