🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Python

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

pandas

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

Q&A

解決済

1回答

1566閲覧

pythonのpandasで条件に応じて行を削除

退会済みユーザー

退会済みユーザー

総合スコア0

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Python

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

pandas

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

0グッド

0クリップ

投稿2019/11/07 05:12

編集2019/11/07 07:18

pythonのpandasでcsvを読み込み、条件に従って行を削除し、新たなファイルに出力したいと考えています。
csvファイル(ファイル名:list1.csv)が以下の時に『time2』に着目し、time2が1.0以下のものの中からtime2の値が小さい順に3つ削除する為には以下のスクリプトで実行できるかと思います。

(list1.csv)
[time1,time2][0.27,0.45][0.28,0.53][0.3309,0.65987][0.36938,0.8952][0.4396,1.0847]........

python

1import pandas as pd 2df = pd.read_csv("list1.csv") 3df_a = (df[df['time2'] < 1.0]) 4print(df_a) 5df_b = df_a.drop([0,1,2]) 6print(df_b)

ここでお聞きしたいのですが、
csvファイルを読み込み、time2に着目することは同じなのですが、
time2が0以上0.5未満の値の行を削除し、それ以外を新たなファイル名(list1_0.5h.csv)として出力、同様にtime2が0.5以上1.0未満の値の行を削除し、それ以外を新たなファイル名(list1_1.0h)として出力、といったようにtime2が5.5以上6.0未満まで同じことを繰り返すにはどのようにしたらよいでしょうか。
尚、time2の値によって行を削除していく中で削除できる行数が5行と制限を加え、削除した行が5行に到達した場合には、それ以降は行を削除することなく、ファイル名を上記のように変更するにはどのようにしたらよいでしょうか。
初歩的な内容で大変恐縮ではありますが、ご教授いただけましたら幸いです。
よろしくお願いいたします。

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

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

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

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

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

magichan

2019/11/07 05:39

> 同様にtime2が0.5以上1.0未満の値の行を削除し、それ以外を新たなファイル名(list1_1.0h)として出力 とありますが、これは元のDataFrameから削除するのですか?それとも以上0.5未満の値を削除したDataFrameから更に削除するのですか?(➡ list1_1.0h に 0.5未満のデータは入るのですか?)
退会済みユーザー

退会済みユーザー

2019/11/07 05:53

元のDataFrameではなく0.5未満1.0以上のファイルには0以上0.5未満で削除したものからさらに削除することとなります。 (0.5以上1.0未満で処理を行う場合には、一つ前で出力されたファイル(list1_0.5h)を読み込み、条件に従い、行を削除し、新たなファイルを(list1_1.0)を出力したいです) わかりにくく、大変失礼いたしました。 よろしくお願いいたします。
magichan

2019/11/07 06:02

その場合、削除する行の上限を設けていると0.5未満の値が紛れている可能性がありますが、それはそのままでよろしいのでしょうか
退会済みユーザー

退会済みユーザー

2019/11/07 07:04 編集

上限を設ける場合(今回は5行削除)、0.5未満の値が10個あった時には残りの5個は削除されないということになりますが、それはそのままで結構でございます。 (これ以降の話はfor文を使用すればよい話になりますが・・・) list1.csv以外に複数のファイル(list1.csv~list1000.csv)があり、ファイルによってtime2の値が異なり、ファイルによっては0以上0.5未満で5行削除し終えてしまう場合もあれば、2.0以上2.5未満でようやく5行削除し終えるといった場合もあると考えております。 いろいろとご注文を付けて申し訳ございませんが、よろしくお願いいたします。
guest

回答1

0

ベストアンサー

まずは、pandas.cut()を使い

Python

1label = pd.cut(df['time2'], bins=np.arange(0, 10.5, 0.5), right=False, labels=False)

のように記述することで、

0.0以上 0.5未満: 0
0.5以上 1.0未満: 1
1.0以上 1.5未満: 2
9.5以上10.0未満: 19

のようにラベルをふることができます。

https://pandas.pydata.org/pandas-docs/version/0.23.4/generated/pandas.cut.html

あとはループにて

Python

1for i in range(20): 2 drop_target = df.loc[label==i].index 3 df.to_csv(f"list1_{(i+1)*0.5:.1f}f.csv")

のように対象となるラベルを順番に削除していくと良いと思います。

削除する行数を制限する場合は

Python

1for i in range(0,20): 2 drop_target = df.loc[label==i,'time2'].sort_values().index[:5] 3 df = df.drop(drop_target) 4 df.to_csv(f"list1_{(i+1)*0.5:.1f}f.csv")

のようにtime2の値でソートして頭からn個のIndex値を対象とすると良いのではないでしょうか。


追記
削除する行数を全体で制限する場合のサンプル

limit = 5 for i in range(0,20): drop_size = min((label == i).sum(), limit) drop_index = df.loc[label==i,'time2'].sort_values().index[:drop_size] df = df.drop(drop_index) df.to_csv(f"list1_{(i+1)*0.5:.1f}f.csv") limit -= drop_size

【追記2】
だいたい、こんな感じになるのではないでしょうか(動作は全く未検証)

Python

1import pandas as pd 2import numpy as np 3 4for list_no in range(1,3): 5 df = pd.read_csv(f"list{list_no}.csv") 6 label = pd.cut(df['time2'], bins=np.arange(0, 10.5, 0.5), right=False, labels=False) 7 8 limit = 5 9 for i in range(0,20): 10 drop_size = min((label == i).sum(), limit) 11 drop_index = df.loc[label==i,'time2'].sort_values().index[:drop_size] 12 df = df.drop(drop_index) 13 new_file = f"list{list_no}_{(i+1)*0.5:.1f}f.csv" 14 df.to_csv(new_file) 15 limit -= drop_size

投稿2019/11/07 07:18

編集2019/11/10 23:28
magichan

総合スコア15898

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

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

退会済みユーザー

退会済みユーザー

2019/11/07 07:21

毎回詳しいご解説ありがとうございます。 教えていただいた内容で、試してみたいと思います。
退会済みユーザー

退会済みユーザー

2019/11/07 07:55 編集

ご教授いただいた内容で実際にやってみました。 舌足らずで申し訳ございません。 現在のスクリプトでやった場合には、各時間帯(各ラベルにおいて)でそれぞれ5行消すことになっているかと思います。 舌足らずで、大変申し訳ないのですが、 ラベル0(0.0以上0.5未満)で5行消した場合にはそれ以降の時間帯では行の削除を行わずに、ファイル名だけを変えて出力したいと思っております。 また、仮にラベル0(0.0以上0.5未満)で条件に該当する行が3行しかない場合にはラベル1(0.5以上1.0未満)で2行削除することとなります。 各時間帯で5行を上限として削除するのではなく、全時間帯で5行(初めにのラベルで5行削除したらそれ以降のラベルでは行削除を行わない)を上限として削除するイメージでしょうか。 私の理解不足・説明不足でご迷惑、お手数をおかけし、大変申し訳ございません。 よろしくお願いいたします。
magichan

2019/11/07 08:22

サンプルを追記しました(未検証ですスミマセン) こんな感じでどうでしょうか
退会済みユーザー

退会済みユーザー

2019/11/07 08:48

ありがとうございます。 実行した結果できました。 お手数をおかけしてしまい、大変失礼いたしました。
退会済みユーザー

退会済みユーザー

2019/11/07 10:48 編集

上記で教えていただいた内容で、複数ファイルで実行しようと思い、 for文を作成したのですが、新たな出力ファイルとして各listとも1.5fのcsvファイルのみしか出力されませんでした。 どのように変更したらよろしいでしょうか。 import pandas as pd import numpy as np for i in range(1,3): df = pd.read_csv(f"list{i}.csv") new_file = f"list{i}_{(i+1)*0.5:.1f}f.csv" label = pd.cut(df['time2'], bins=np.arange(0, 10.5, 0.5), right=False, labels=False) limit = 5 for i in range(0,20): drop_size = min((label == i).sum(), limit) drop_index = df.loc[label==i,'time2'].sort_values().index[:drop_size] df = df.drop(drop_index) df.to_csv(new_file) limit -= drop_size 何度も何度も大変申し訳ございません。 ご教授いただけましたら幸いです。
magichan

2019/11/07 10:53

ファイル名の生成部 new_file = f"list{i}_{(i+1)*0.5:.1f}f.csv" をループの中に移動してみてください
退会済みユーザー

退会済みユーザー

2019/11/07 14:06

知識が乏しくて申し訳ございません。 for文を使ったループは2か所存在(両方変数(?)はi)するかと思いますが、このような場合どちらかの変数をi以外の文字にしないとうまくいかないのでしょうか? ご丁寧に教えていただいているのに、自分の知識のなさのせいで、理解できずに大変申し訳ないです。
magichan

2019/11/07 23:33

コメント欄はインデントが無効のため、コードを正確に把握できないのですが、このコードにおいて最初のforループはどの行までをループしているのでしょうか?(new_file=... の行までという認識でただしいですか?)
退会済みユーザー

退会済みユーザー

2019/11/08 13:32

最初のforループはおっしゃるとおり、new_file = f"list{i}_{(i+1)*0.5:.1f}f.csv"までループしております。
退会済みユーザー

退会済みユーザー

2019/11/08 13:36 編集

申し訳ございません。よろしくお願いいたします。
退会済みユーザー

退会済みユーザー

2019/11/11 02:18

ありがとうございました。 ご教授いただいた内容で解決できました。 for文の中にfor文がある場合について構造を学習させていただきました。 最後までご丁寧にご教授いただき本当にありがとうございました。
退会済みユーザー

退会済みユーザー

2019/11/20 05:11 編集

>magichan様 追記2のlimit=5についてになりますが、これは必ず5行を削除するという意味でしょうか。 読み込むファイルによっては、削除できる行が5行以下の場合もあるのですが、 そうした場合にはどのように変更すればよいのでしょうか。 ご教授いただけましたら幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問