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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pandas

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

Q&A

解決済

1回答

1444閲覧

DataFrame内の値の代入の高速化

amaturePy

総合スコア131

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pandas

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

0グッド

0クリップ

投稿2021/07/10 07:22

編集2021/07/10 09:22

前回質問の続きのコードになります。
頂いた回答を元に以下の処理まで実装できております。
データ数は7000行*10列の70,000ほどになります。

①各セルの値が0以外の場合+cv_date列の同一行が0で無い場合(日付)が入っているか判定 ②でTrueの場合、各セルの日付からcv_dateまでの日付を引き算で計算し、変数に格納 ③各セルの元々日付の入っていたセルに③の結果の値を更新する

この上記の処理後に各行ごとの数字で最小の値の位置に1を代入し、それ以外を残ったtimestamp型のデータも含めて0にしようとしています。
その中の最小のセルを1にするという処理で.locや.atを使っているのですが、処理が一向に終わらず、PCの方も熱くなっているようで、なんとか高速化できないか方法を探しています。

何か良い方法やメソッドなどがありましたらご教授頂きたいです。
よろしくお願いします。

df = pd.concat((push_start_df,cv_date_df), axis=1) df['cv_date'] = pd.to_datetime(df['cv_date'], errors='coerce') cv = pd.notnull(df['cv_date']) #cv_dateが有効な行 for c in df.columns: if c != 'cv_date': df[c] = pd.to_datetime(df[c], errors='coerce') rows = (cv) & (pd.notnull(df[c])) df2 = df[rows] gap = df2['cv_date'] - df2[c] df.loc[rows,c] = gap.dt.days df3 = df[df.columns[df.columns != 'cv_date']] min_col = df3.idxmin(axis=1) #最小の値のカラムを取得 df.at[rows,min_col] = 1 #各行の最小の値のセルを1に変換

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

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

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

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

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

guest

回答1

0

ベストアンサー

python

1import pandas as pd 2from io import StringIO 3from datetime import datetime 4 5# テストデータ 6s = """a_date,b_date,cv_date 72021-07-01,2021-07-02,2021-07-10 8,,2021-07-11 92021-07-02,,2021-07-11 10,2021-07-03,2021-07-12""" 11df = pd.read_csv(StringIO(s)) 12 13cv = pd.notnull(df['cv_date']) # cv_dateが有効な行 14 15df = df.loc[cv,:].apply(lambda x:pd.to_datetime(x, errors='coerce')).copy() 16cols=df.columns.drop('cv_date') 17df_mins=df.loc[:,cols].apply(lambda x: (df['cv_date'] - x).dt.days).assign( 18 mins = lambda x: x.min(axis=1) 19) 20df_mins.drop('mins',axis=1).apply(lambda x: x==df_mins['mins']) 21

サンプルデータがないのでなんとも言えませんが、forが遅さの原因だと思いました。

forを使用しなくても、cv_dateとの計算や最低値を1(True)その他を0(False)はこのように可能だと思います。

python

1# 読み込み等は上記と一緒 2 3df = df.loc[cv,:].apply(lambda x:pd.to_datetime(x, errors='coerce')).copy() # cv_dateが有効な行を抽出すると共に、datetime型にデータを変更したデータフレームを作成 4 5cols=df.columns.drop('cv_date') # cv_date以外の列名 6 7# cv_dateとの差が一番小さい = その日付が一番大きい ということで、 8# 日付の最大値と比較した結果とcv_dateを結合してデータフレームを戻している 9pd.concat([df.loc[:,cols].apply(lambda x: x == np.max(x) ,axis=1),df['cv_date']],axis=1)

のほうが手順が少ないですね。

投稿2021/07/10 12:42

編集2021/07/10 13:17
toshikawa

総合スコア388

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

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

amaturePy

2021/07/10 15:12

ありがとうございます!確かにTrue or Falseで要件満たせました。なぜか1を立てようとしてました。 pandasは処理に気をつけてあげないと極端に処理に時間を要するとは見たことあるものの、.atなどの一文でここまで変わるとは驚きました。 また、頂いたコード、自分の知識不足ですがなんとか自分のものにして自由にこのように書けるように勉強させて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問