3

pandas.Dataframe で使用するために numpy.ndarray の dict にデータを直接ロードする python モジュールがあります。ただし、「NA」値に問題があることに気付きました。私のファイル形式は、NA 値を -9223372036854775808 (boost::integer_traits::const_min) として表します。NA 以外の値が期待どおりに (正しい値で) pandas.Dataframe に読み込まれています。私のモジュールが numpy.datetime64 ndarray にロードされ、それが pandas.tslib.Timestamp のリストに変換されるということが起こっていると思います。この変換は、'const_min' 整数を保持していないようです。次のことを試してください。

>>> pandas.tslib.Timestamp(-9223372036854775808)
NaT
>>> pandas.tslib.Timestamp(numpy.datetime64(-9223372036854775808))
<Timestamp: 1969-12-31 15:58:10.448384>

これはパンダのバグですか?この場合、モジュールで numpy.ndarray の使用を回避し、Pandas がトリップしないものを使用できると思います (おそらく、tslib.Timestamp 自体のリストを事前に割り当てます)。

予期しないことが起こる別の例を次に示します。

>>> npa = numpy.ndarray(1, dtype=numpy.datetime64)
>>> npa[0] = -9223372036854775808
>>> pandas.Series(npa)
0   NaT
>>> pandas.Series(npa)[0]
<Timestamp: 1969-12-31 15:58:10.448384>

以下の Jeff のコメントに続いて、何がうまくいかないのかについての詳細情報があります。

>>> npa = numpy.ndarray(2, dtype=numpy.int64)
>>> npa[0] = -9223372036854775808
>>> npa[1] = 1326834000090451
>>> npa
array([-9223372036854775808,     1326834000090451])
>>> s_npa = pandas.Series(npa, dtype='M8[us]')
>>> s_npa
0                          NaT
1   2012-01-17 21:00:00.090451

わーい!このシリーズは、NA と私のタイムスタンプを保持していました。ただし、そのシリーズから DataFrame を作成しようとすると、NaT が消えます。

>>> pandas.DataFrame({'ts':s_npa})
                      ts
0 1969-12-31 15:58:10.448384
1 2012-01-17 21:00:00.090451

うーん。気まぐれで、代わりにエポックを過ぎたナノ秒として整数を解釈してみました。驚いたことに、DataFrame は正しく機能しました。

s2_npa = pandas.Series(npa, dtype='M8[ns]')
>>> s2_npa
0                             NaT
1   1970-01-16 08:33:54.000090451
>>> pandas.DataFrame({"ts":s2_npa})
                             ts
0                           NaT
1 1970-01-16 08:33:54.000090451

もちろん、私のタイムスタンプは正しくありません。私のポイントは、ここで pandas.DataFrame の動作に一貫性がないということです。dtype='M8[ns]' を使用すると NaT が保持されるのに、'M8[us]' を使用すると保持されないのはなぜですか?

現在、この回避策を使用して を変換しています。これにより、処理がかなり遅くなりますが、機能します。

>>> s = pandas.Series([1000*ts if ts != -9223372036854775808 else ts for ts in npa], dtype='M8[ns]')
>>> pandas.DataFrame({'ts':s})
                          ts
0                        NaT
1 2012-01-17 21:00:00.090451

(数時間後…)

わかりました、私は進歩しています。Series のrepr関数が最終的に「_format_datetime64」を呼び出し、「isnull」をチェックして「NaT」を出力することを理解するために、コードを詳しく調べました。

>>> pandas.Series(npa)
0   NaT
>>> pandas.Series(npa)[0]
<Timestamp: 1969-12-31 15:58:10.448384>

前者は NA を尊重しているように見えますが、これは印刷時にのみ行われます。「isnull」を呼び出し、回答に基づいて動作する他の pandas 関数があると思います。この場合、NA タイムスタンプに対して部分的に機能するように見えるかもしれません。ただし、要素ゼロのタイプにより、シリーズが正しくないことはわかっています。これはTimestampですが、 NaTTypeである必要があります。次のステップは、Series のコンストラクターに飛び込んで、構築中に pandas がNaT値をいつ/どのように使用するかを把握することです。おそらく、dtype='M8[us]'... を指定すると、ケースが欠落している可能性があります (詳細は後述)。

コメントでの Andy の提案に従って、pandas Timestamp を使用して問題を解決しようとしました。うまくいきませんでした。これらの結果の例を次に示します。

>>> npa = numpy.ndarray(1, dtype='i8')
>>> npa[0] = -9223372036854775808
>>> npa
array([-9223372036854775808])
>>> pandas.tslib.Timestamp(npa.view('M8[ns]')[0]).value
-9223372036854775808
>>> pandas.tslib.Timestamp(npa.view('M8[us]')[0]).value
-28909551616000
4

1 に答える 1

2

答え: いいえ

技術的に言えば、そうです。私は github にバグを投稿し、ここで応答を得ました: https://github.com/pydata/pandas/issues/2800#issuecomment-13161074

「ナノ秒以外の単位は、インデックス作成などでは現在サポートされていません。これは厳密に実施する必要があります」

「us」ではなく「ns」で実行したすべてのテストは正常に動作します。今後のリリースが楽しみです。

興味のある方のために、C++ Python モジュールを変更して、ディスクからロードした int64_t 配列を反復処理し、NA 値 (boost::integer_traits::const_min) を除いてすべてを 1000 で乗算します。パフォーマンスが心配でしたが、ロード時間の違いは私にとってはわずかです。(Python で同じことを行うと、非常に遅くなります。)

于 2013-02-06T18:03:22.210 に答える