2016-09-22 10 views
2

私は、タイムゾーンの列とdatetimeの列を持つデータフレームを持っています。これらのデータをUTCに変換して他のデータと結合したい場合は、UTCから視聴者のローカルタイムゾーンに変換する計算が必要になります。Pandasは別のタイムゾーン列を使用してdatetimeを変換します

datetime    time_zone 
2016-09-19 01:29:13 America/Bogota 
2016-09-19 02:16:04 America/New_York 
2016-09-19 01:57:54 Africa/Cairo 

def create_utc(df, column, time_format='%Y-%m-%d %H:%M:%S'): 
    timezone = df['TZ'] 
    df[column + '_utc'] = df[column].dt.tz_localize(timezone).dt.tz_convert('UTC').dt.strftime(time_format) 
    df[column + '_utc'].replace('NaT', np.nan, inplace=True) 
    df[column + '_utc'] = pd.to_datetime(df[column + '_utc']) 
    return df 

これは私の間違った試みでした。エラーは、 'timezone'変数が列を参照しているために真実があいまいであるということです。同じ行の値をどのように参照するのですか?

編集:データ(394,000行と22の固有のタイムゾーン)の下の回答から、いくつかの結果があります。 Edit2:誰かが結果を見たい場合に備えてgroupbyの例を追加しました。はるかに速いです。

%%timeit 

for tz in df['TZ'].unique(): 
    df.ix[df['TZ'] == tz, 'datetime_utc2'] = df.ix[df['TZ'] == tz, 'datetime'].dt.tz_localize(tz).dt.tz_convert('UTC') 
df['datetime_utc2'] = df['datetime_utc2'].dt.tz_localize(None) 

1 loops, best of 3: 1.27 s per loop

%%timeit 

df['datetime_utc'] = [d['datetime'].tz_localize(d['TZ']).tz_convert('UTC') for i, d in df.iterrows()] 
df['datetime_utc'] = df['datetime_utc'].dt.tz_localize(None) 

1 loops, best of 3: 50.3 s per loop

df['datetime_utc'] = pd.concat([d['datetime'].dt.tz_localize(tz).dt.tz_convert('UTC') for tz, d in df.groupby('TZ')]) 



**1 loops, best of 3: 249 ms per loop** 

答えて

3

はベクトル化手法であります(ループする:df.time_zone.nunique()回):

In [2]: t 
Out[2]: 
      datetime   time_zone 
0 2016-09-19 01:29:13 America/Bogota 
1 2016-09-19 02:16:04 America/New_York 
2 2016-09-19 01:57:54  Africa/Cairo 
3 2016-09-19 11:00:00 America/Bogota 
4 2016-09-19 12:00:00 America/New_York 
5 2016-09-19 13:00:00  Africa/Cairo 

In [3]: for tz in t.time_zone.unique(): 
    ...:   mask = (t.time_zone == tz) 
    ...:   t.loc[mask, 'datetime'] = \ 
    ...:    t.loc[mask, 'datetime'].dt.tz_localize(tz).dt.tz_convert('UTC') 
    ...: 

In [4]: t 
Out[4]: 
      datetime   time_zone 
0 2016-09-19 06:29:13 America/Bogota 
1 2016-09-19 06:16:04 America/New_York 
2 2016-09-18 23:57:54  Africa/Cairo 
3 2016-09-19 16:00:00 America/Bogota 
4 2016-09-19 16:00:00 America/New_York 
5 2016-09-19 11:00:00  Africa/Cairo 

UPDATE:

In [12]: df['new'] = df.groupby('time_zone')['datetime'] \ 
         .transform(lambda x: x.dt.tz_localize(x.name)) 

In [13]: df 
Out[13]: 
      datetime   time_zone     new 
0 2016-09-19 01:29:13 America/Bogota 2016-09-19 06:29:13 
1 2016-09-19 02:16:04 America/New_York 2016-09-19 06:16:04 
2 2016-09-19 01:57:54  Africa/Cairo 2016-09-18 23:57:54 
3 2016-09-19 11:00:00 America/Bogota 2016-09-19 16:00:00 
4 2016-09-19 12:00:00 America/New_York 2016-09-19 16:00:00 
5 2016-09-19 13:00:00  Africa/Cairo 2016-09-19 11:00:00 
+0

私はこれを答えとして投票します。私は他の答えのためにほぼ1分に対して320k行以上のサブ1秒の速度を得ています。私はちょうど誰かが私もテストすることができますgroupbyスニペットを共有することを望んでいます。 – trench

1

あなたの問題は、tz_localize()だけスカラー値をとることができるということですので、我々は、データフレームを反復処理する必要があります:

df['datetime_utc'] = [d['datetime'].tz_localize(d['time_zone']).tz_convert('UTC') for i,d in df.iterrows()] 

結果は:

  datetime   time_zone    datetime_utc 
0 2016-09-19 01:29:13 America/Bogota 2016-09-19 06:29:13+00:00 
1 2016-09-19 02:16:04 America/New_York 2016-09-19 06:16:04+00:00 
2 2016-09-19 01:57:54  Africa/Cairo 2016-09-18 23:57:54+00:00 

代替的なアプローチは、タイムゾーンによってグループにあり、1回のパスで全て一致する行を変換する:ここ

df['datetime_utc'] = pd.concat([d['datetime'].dt.tz_localize(tz).dt.tz_convert('UTC') for tz, d in df.groupby('time_zone')]) 
+0

が、私はこれを試してみましょう。私はちょうど列挙したり、iterrowsの周りにいたことはありません。私はこれらのコマンドをいつ使うのか分かりません – trench

+1

これを行う方法は、time_zoneのトランスフォームを使ってgroupbyに変換して、そのゾーンをすべて変換することです - iirc iはこれをi問題と一度解決しました – Jeff

+0

私はあなたの回答履歴を見てみましたが、それを見てください。上記の方法はうまくいくように見えましたが、あなたがそれを見つけた場合、groupbyの例を見るのはクールです。毎月約2milの行にこれを実行していますので、各メソッドの速度をテストするのがいいでしょう。 – trench

関連する問題