再現可能なパンダの良い例を作る方法


221

両方を見てかなりの時間を費やしてきた そして SOのタグ、私が得る印象は、pandas質問が再現可能なデータを含む可能性が低いということです。これはRコミュニティが奨励することにかなり優れているものであり、このようなガイドのおかげで、新規参入者はこれらの例をまとめるのにある程度の助けを得ることができます。これらのガイドを読んで再現性のあるデータを返すことができる人は、多くの場合、自分の質問に対する答えを得るのがはるかにうまくいきます。

pandas質問の再現可能な良い例をどのように作成できますか?単純なデータフレームをまとめることができます。例:

import pandas as pd
df = pd.DataFrame({'user': ['Bob', 'Jane', 'Alice'], 
                   'income': [40000, 50000, 42000]})

しかし、多くのサンプルデータセットには、より複雑な構造が必要です。例:

  • datetime インデックスまたはデータ
  • 複数のカテゴリー変数(Rのexpand.grid()関数に相当するものがあります。これは、いくつかの指定された変数のすべての可能な組み合わせを生成しますか?)
  • MultiIndexまたはPanelデータ

数行のコードを使用してモックアップするのが難しいデータセットの場合、データ構造dput()を再生成するためにコピー/ペースト可能なコードを生成できるRに相当するものはありますか?


8
印刷の出力をコピーする場合、MultiIndex:sを除いて、ほとんどの場合、回答者はread_clipboard()...を使用できます。それを言って、dictは良い追加です
Andy Hayden

8
アンディが言ったことに加えて、私はコピー貼り付けと思いますdf.head(N).to_dict()。どこNにいくらか合理的な数があるのが良い方法です。プリティラインブレークを出力に追加するためのボーナス+1。タイムスタンプの場合、通常from pandas import Timestampはコードの先頭に追加するだけです。
Paul H

回答:


323

注意:ここでのアイデアは確かに、スタックオーバーフローのためにかなり一般的なものです質問

免責事項:良い質問を書くことは難しいです。

いいもの:

  • small *のサンプルDataFrameを実行可能なコードとして含めます。

    In [1]: df = pd.DataFrame([[1, 2], [1, 3], [4, 6]], columns=['A', 'B'])

    またはを使用して「コピーして貼り付け可能」にするとpd.read_clipboard(sep='\s\s+')、スタックオーバーフローのハイライトのテキストをフォーマットしてCtrl+ K(または各行に4つのスペースを追加)を使用するか、コードをインデントせずにコードの上下に3つのチルドを配置できます。

    In [2]: df
    Out[2]: 
       A  B
    0  1  2
    1  1  3
    2  4  6
    

    pd.read_clipboard(sep='\s\s+')自分でテストしてください。

    * 私は本当に意味ですか小さなを、例えばデータフレームの大半は6行がより少ない可能性が要出典、と私は5行でそれを行うことができます賭けます。df = df.head()あなたが直面している問題を示す小さなDataFrameを構成できるかどうかを確認するために、いじらない場合は、でエラーを再現できますか?

    * すべてのルールには例外があり、明らかなものはパフォーマンスの問題(この場合は必ず%timeitを使用し、場合によっては%prunを使用します)です。ここで生成する必要があります(np.random.seedを使用して、まったく同じフレームになるようにします)df = pd.DataFrame(np.random.randn(100000000, 10))。それを言って、「私のためにこのコードを速くしてください」はサイトのトピックに厳密ではありません...

  • あなたが望む結果を書き出す(上記と同様)

    In [3]: iwantthis
    Out[3]: 
       A  B
    0  1  5
    1  4  6
    

    数値の由来を説明します。5は、Aが1である行のB列の合計です。

  • あなたが試したコードを表示しください:

    In [4]: df.groupby('A').sum()
    Out[4]: 
       B
    A   
    1  5
    4  6
    

    しかし、何が間違っているかを言います。A列は、列ではなくインデックスにあります。

  • あなたがやったいくつかの研究(表示されないドキュメントを検索しStackOverflowの検索を)、要約を与えます:

    sumのdocstringは単に「グループ値の合計を計算する」と述べています

    GROUPBYのドキュメントは、このための任意の例を与えることはありません。

    余談ですが、ここでの答えはを使用することdf.groupby('A', as_index=False).sum()です。

  • タイムスタンプ列があることが関連している場合、たとえば、リサンプリングなどの場合は、明示的にpd.to_datetimeして、適切な測定のためにそれらに適用します**。

    df['date'] = pd.to_datetime(df['date']) # this column ought to be date..

    ** 時々これが問題そのものです:それらは文字列でした。

悪い人:

  • コピーして貼り付けることができない MultiIndexを含めないでください(上記を参照)。これは、パンダのデフォルト表示の一種の不満ですが、それでも迷惑です。

    In [11]: df
    Out[11]:
         C
    A B   
    1 2  3
      2  6
    

    正しい方法は、通常のDataFrameをset_index呼び出しに含めることです。

    In [12]: df = pd.DataFrame([[1, 2, 3], [1, 2, 6]], columns=['A', 'B', 'C']).set_index(['A', 'B'])
    
    In [13]: df
    Out[13]: 
         C
    A B   
    1 2  3
      2  6
    
  • あなたが望む結果を与えるときにそれが何であるかについての洞察を提供してください:

       B
    A   
    1  1
    5  0
    

    数値の取得方法(具体的には何ですか)について具体的に説明してください...数値が正しいことを再確認してください。

  • コードがエラーをスローする場合は、スタックトレース全体を含めてください(ノイズが多すぎる場合は、後で編集できます)。行番号(およびそれが発生させるコードの対応する行)を表示します。

ぶさいく:

  • アクセス権のないcsvにリンクしない(理想的には、外部ソースにリンクしないでください...)

    df = pd.read_csv('my_secret_file.csv')  # ideally with lots of parsing options

    ほとんどのデータは独自のものであり、それを取得します。同様のデータを作成し、問題(小さなもの)を再現できるかどうかを確認します。

  • 「大規模」なDataFrameがあるように、状況を曖昧に言葉で説明しないでください。列名の一部を渡してください(dtypeは言及しないでください)。実際のコンテキストを確認せずに、完全に無意味なものについて、詳細を調べてみてください。たぶん、この段落の最後まで読む人すらいないでしょう。

    エッセイは悪いです、それは小さな例で簡単です。

  • 実際の質問に進む前に、10行以上(100以上??)のデータ変更行を含めないでください。

    私たちの日常の仕事でこれを十分に見てください。私たちは、しかし、助けたいではない。このような...
    イントロをカットし、問題の原因となっているステップで関連するデータフレーム(またはそれらの小さいバージョン)を表示するだけです。

とにかく、Python、NumPy、Pandasを楽しく学んでください!


30
pd.read_clipboard(sep='\s\s+')チップの+1 。私はSO、特別しかし簡単に共有データフレームを必要とする質問投稿する場合は、この1のように、私はExcelでそれを構築しSOersが同じことを行うには、次に指示し、私のクリップボードにコピーします。時間を大幅に節約できます。
zelusp

1
pd.read_clipboard(sep='\s\s+')大規模なデータセットが多数存在するリモートサーバーでPythonを使用している場合、この提案は機能しないようです。
user5359531 16

1
なぜpd.read_clipboard(sep='\s\s+')pd.read_clipboard()(デフォルトでは‘s+’)単純ではないのですか?最初の文字には少なくとも2つの空白文字が必要であり、1つしかない場合に問題が発生する可能性があります(たとえば、@ JohnEの回答でそのようにしてください)。
MarianD 2018

3
@MarianDは、\ s \ s +が非常に人気がある理由は、列名などに1つあることが多いためです。これはおもちゃ/小さなデータセットのためのものなので、かなり強力で大多数のケースです。注:分離されたタブは別の話になりますが、stackoverflowはタブをスペースに置き換えますが、tsvがある場合は、\ tを使用します。
アンディヘイデン

3
ええと、私は常に使用しますpd.read_clipboard()。それらがスペースの場合、次のようにします。pd.read_clipboard(sep='\s+{2,}', engine='python'):P
U10-Forward

72

サンプルデータセットの作成方法

これは主に、サンプルデータフレームを作成する方法の例を提供することにより、@ AndyHaydenの回答を拡張するためのものです。Pandasと(特に)numpyを使用すると、このためのさまざまなツールが提供され、通常は数行のコードで実際のデータセットの合理的な複製を作成できます。

numpyとpandasをインポートした後、データと結果を正確に再現できるようにしたい場合は、ランダムシードを提供してください。

import numpy as np
import pandas as pd

np.random.seed(123)

台所の流しの例

さまざまなことができる例を次に示します。すべての種類の有用なサンプルデータフレームは、このサブセットから作成できます。

df = pd.DataFrame({ 

    # some ways to create random data
    'a':np.random.randn(6),
    'b':np.random.choice( [5,7,np.nan], 6),
    'c':np.random.choice( ['panda','python','shark'], 6),

    # some ways to create systematic groups for indexing or groupby
    # this is similar to r's expand.grid(), see note 2 below
    'd':np.repeat( range(3), 2 ),
    'e':np.tile(   range(2), 3 ),

    # a date range and set of random dates
    'f':pd.date_range('1/1/2011', periods=6, freq='D'),
    'g':np.random.choice( pd.date_range('1/1/2011', periods=365, 
                          freq='D'), 6, replace=False) 
    })

これにより、以下が生成されます。

          a   b       c  d  e          f          g
0 -1.085631 NaN   panda  0  0 2011-01-01 2011-08-12
1  0.997345   7   shark  0  1 2011-01-02 2011-11-10
2  0.282978   5   panda  1  0 2011-01-03 2011-10-30
3 -1.506295   7  python  1  1 2011-01-04 2011-09-07
4 -0.578600 NaN   shark  2  0 2011-01-05 2011-02-27
5  1.651437   7  python  2  1 2011-01-06 2011-02-03

いくつかのメモ:

  1. np.repeatand np.tile(列de)は、非常に規則的な方法でグループとインデックスを作成するのに非常に役立ちます。2列の場合、これはrを簡単に複製するために使用できますがexpand.grid()、すべての順列のサブセットを提供する機能がより柔軟です。ただし、3列以上の場合、構文はすぐに扱いにくくなります。
  2. rのより直接的な置き換えについては、pandasクックブックの解決策またはここに示す解決策をexpand.grid()参照してください。それらは任意の数の次元を許可します。itertoolsnp.meshgrid
  3. でかなりのことができますnp.random.choice。たとえば、列gには、2011年から6つの日付をランダムに選択しています。さらに、replace=Falseこれらの日付が一意であることを確認することができます。これを一意の値を持つインデックスとして使用する場合に非常に便利です。

偽の株式市場データ

上記のコードのサブセットを取得することに加えて、テクニックを組み合わせてほとんど何でも行うことができます。例えば、ここに組み合わせた簡単な例だnp.tiledate_range、同じ日付をカバーする4つの銘柄のサンプルティッカー・データを作成するには:

stocks = pd.DataFrame({ 
    'ticker':np.repeat( ['aapl','goog','yhoo','msft'], 25 ),
    'date':np.tile( pd.date_range('1/1/2011', periods=25, freq='D'), 4 ),
    'price':(np.random.randn(100).cumsum() + 10) })

これで100行のサンプルデータセット(ティッカーごとに25日付)が作成されましたが、4行しか使用していないため、他の人が100行のコードをコピーして貼り付けることなく簡単に再現できます。質問の説明に役立つ場合は、データのサブセットを表示できます。

>>> stocks.head(5)

        date      price ticker
0 2011-01-01   9.497412   aapl
1 2011-01-02  10.261908   aapl
2 2011-01-03   9.438538   aapl
3 2011-01-04   9.515958   aapl
4 2011-01-05   7.554070   aapl

>>> stocks.groupby('ticker').head(2)

         date      price ticker
0  2011-01-01   9.497412   aapl
1  2011-01-02  10.261908   aapl
25 2011-01-01   8.277772   goog
26 2011-01-02   7.714916   goog
50 2011-01-01   5.613023   yhoo
51 2011-01-02   6.397686   yhoo
75 2011-01-01  11.736584   msft
76 2011-01-02  11.944519   msft

2
すばらしい答えです。この質問を書いた後、実際にパンダのクックブックにexpand.grid()含まれている非常に短く単純な実装を作成しました。それを回答に含めることもできます。あなたの答えは、私の関数が処理できるよりも複雑なデータセットを作成する方法を示しています。これは素晴らしいことです。expand_grid()
マリウス

46

回答者の日記

質問をするための私の最高のアドバイスは、質問に答える人々の心理学について遊ぶことです。私はそれらの人々の1人であるので、なぜ私が特定の質問に答えるのか、なぜ他の人には答えないのかについて洞察を与えることができます。

動機

いくつかの理由で質問に答えたいと思っています

  1. Stackoverflow.comは私にとって非常に貴重なリソースでした。還元したかった。
  2. 私が還元する努力の中で、このサイトは以前よりもさらに強力なリソースであることがわかりました。質問に答えることは私にとって学習経験であり、私は学びたいです。 この回答を読んで、別の獣医からコメントしてください。このようなやり取りは私を幸せにします。
  3. ポイントが好き!
  4. #3を参照してください。
  5. 面白い問題が好きです。

私の最も純粋な意図はすべてすばらしいですが、1つまたは30の質問に答えると、その満足感が得られますどの質問に答えるかの 私の選択駆り立てるものは、ポイント最大化の大きな要素です。

私は興味深い問題にも時間を費やしますが、それは数少ないので、興味のない質問の解決策を必要とする質問者には役立ちません。私に質問に答えさせる最善の策は、可能な限り少ない努力で答えられるように、熟成した大皿にその質問を提供することです。2つの質問を見ていて、1つにコードがある場合は、貼り付けをコピーして、必要なすべての変数を作成できます。時間があれば多分もう一回戻ってきます。

主なアドバイス

質問に答える人が簡単にできるようにします。

  • 必要な変数を作成するコードを提供します。
  • そのコードを最小化します。投稿を見ているときに目が眩んでいる場合は、次の質問に進むか、他に行っていることすべてに戻ります。
  • あなたが求めていることを考え、具体的に考えてください。自然言語(英語)は不正確で混乱しているので、私たちはあなたが何をしたかを見たいと思います。あなたが試したもののコードサンプルは、自然言語の説明の不一致を解決するのに役立ちます。
  • あなたが期待するものを示してください!!! 私は座って物事を試さなければなりません。いくつかのことを試してみないと、質問に対する答えはほとんどわかりません。あなたが探しているものの例が見つからない場合、私は推測する気がしないので、質問を渡すかもしれません。

あなたの評判はあなたの評判以上のものです。

私はポイントが好きです(私はその点について前述しました)。しかし、それらの点は本当に私の評判ではありません。私の本当の評判は、サイト上の他の人が私をどう思うかを融合したものです。私は公正で正直であるよう努めており、他の人がそれを見ることができることを望んでいます。質問者にとってそれが意味することは、質問者の行動を覚えています。回答を選択せず​​、適切な回答を支持しない場合、覚えています。私が嫌いな振る舞いや私が好きな振る舞いをするなら、覚えています。これは、私が答える質問にも関係しています。


とにかく、私はおそらく続けることができますが、私は実際にこれを読んだすべての人を惜しまないでしょう。


26

チャレンジ SOの質問への応答の中で最も挑戦的な側面の一つは、それが(データを含む)問題を再現するのにかかる時間です。データを再現する明確な方法がない質問は、回答される可能性が低くなります。時間をかけて質問を書いていて、助けてほしい問題がある場合、他の人が問題を解決するために使用できるデータを提供することで、簡単に自分を助けることができます。

良いパンダの質問を書くために@Andyが提供する指示は、始めるのに最適な場所です。詳細については、質問する方法と、最小、完全、検証可能な例を作成する方法を参照してください。

質問を前もって明確に述べてください。 時間をかけて質問とサンプルコードを作成したら、それを読んで、問題を要約し、質問を明確に示す「エグゼクティブサマリ」を読者に提供してください。

元の質問

このデータがあります...

私はこれをしたい...

結果がこのように見えるようにしたい...

しかし、これを行おうとすると、次の問題が発生します...

私は[これ]と[それ]で解決策を見つけようとしました。

どうすれば修正できますか?

提供されるデータ、サンプルコード、エラースタックの量に応じて、読者は問題が何であるかを理解する前に長い道のりを進む必要があります。質問自体が一番上になるように質問を書き直してみてから、必要な詳細を入力してください。

改訂された質問

質問: [これ]を行うにはどうすればよいですか?

私は[これ]と[それ]で解決策を見つけようとしました。

[これ]を実行しようとすると、次の問題が発生します...

私の最終結果がこのように見えるようにしたい...

これが私の問題を再現できる最小限のコードです...

そして、これが私のサンプルデータを再作成する方法です: df = pd.DataFrame({'A': [...], 'B': [...], ...})

必要に応じてサンプルデータを提供してください!!!

DataFrameの先頭または末尾だけで十分な場合もあります。また、@ JohnEによって提案された方法を使用して、他の人が複製できるより大きなデータセットを作成することもできます。彼の例を使用して、株価の100行のDataFrameを生成します。

stocks = pd.DataFrame({ 
    'ticker':np.repeat( ['aapl','goog','yhoo','msft'], 25 ),
    'date':np.tile( pd.date_range('1/1/2011', periods=25, freq='D'), 4 ),
    'price':(np.random.randn(100).cumsum() + 10) })

これが実際のデータである場合は、次のようにデータフレームの先頭または末尾、あるいはその両方を含めることができます(機密データは必ず匿名化してください)。

>>> stocks.head(5).to_dict()
{'date': {0: Timestamp('2011-01-01 00:00:00'),
  1: Timestamp('2011-01-01 00:00:00'),
  2: Timestamp('2011-01-01 00:00:00'),
  3: Timestamp('2011-01-01 00:00:00'),
  4: Timestamp('2011-01-02 00:00:00')},
 'price': {0: 10.284260107718254,
  1: 11.930300761831457,
  2: 10.93741046217319,
  3: 10.884574289565609,
  4: 11.78005850418319},
 'ticker': {0: 'aapl', 1: 'aapl', 2: 'aapl', 3: 'aapl', 4: 'aapl'}}

>>> pd.concat([stocks.head(), stocks.tail()], ignore_index=True).to_dict()
{'date': {0: Timestamp('2011-01-01 00:00:00'),
  1: Timestamp('2011-01-01 00:00:00'),
  2: Timestamp('2011-01-01 00:00:00'),
  3: Timestamp('2011-01-01 00:00:00'),
  4: Timestamp('2011-01-02 00:00:00'),
  5: Timestamp('2011-01-24 00:00:00'),
  6: Timestamp('2011-01-25 00:00:00'),
  7: Timestamp('2011-01-25 00:00:00'),
  8: Timestamp('2011-01-25 00:00:00'),
  9: Timestamp('2011-01-25 00:00:00')},
 'price': {0: 10.284260107718254,
  1: 11.930300761831457,
  2: 10.93741046217319,
  3: 10.884574289565609,
  4: 11.78005850418319,
  5: 10.017209045035006,
  6: 10.57090128181566,
  7: 11.442792747870204,
  8: 11.592953372130493,
  9: 12.864146419530938},
 'ticker': {0: 'aapl',
  1: 'aapl',
  2: 'aapl',
  3: 'aapl',
  4: 'aapl',
  5: 'msft',
  6: 'msft',
  7: 'msft',
  8: 'msft',
  9: 'msft'}}

また、(関連する列のみを使用して)DataFrameの説明を提供することもできます。これにより、他のユーザーが各列のデータ型を確認し、他の一般的なエラー(たとえば、文字列としての日付とdatetime64とオブジェクトの比較)を特定しやすくなります。

stocks.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 100 entries, 0 to 99
Data columns (total 3 columns):
date      100 non-null datetime64[ns]
price     100 non-null float64
ticker    100 non-null object
dtypes: datetime64[ns](1), float64(1), object(1)

注:DataFrameにマルチインデックスがある場合:

DataFrameにマルチインデックスがある場合、を呼び出す前に、まずリセットする必要がありますto_dict。次に、次を使用してインデックスを再作成する必要がありますset_index

# MultiIndex example.  First create a MultiIndex DataFrame.
df = stocks.set_index(['date', 'ticker'])
>>> df
                       price
date       ticker           
2011-01-01 aapl    10.284260
           aapl    11.930301
           aapl    10.937410
           aapl    10.884574
2011-01-02 aapl    11.780059
...

# After resetting the index and passing the DataFrame to `to_dict`, make sure to use 
# `set_index` to restore the original MultiIndex.  This DataFrame can then be restored.

d = df.reset_index().to_dict()
df_new = pd.DataFrame(d).set_index(['date', 'ticker'])
>>> df_new.head()
                       price
date       ticker           
2011-01-01 aapl    10.284260
           aapl    11.930301
           aapl    10.937410
           aapl    10.884574
2011-01-02 aapl    11.780059

12

これが、dputPandas DataFrameの私のバージョン-再現可能なレポートを作成するための標準Rツールです。より複雑なフレームでは失敗する可能性がありますが、単純なケースではうまくいくようです:

import pandas as pd
def dput (x):
    if isinstance(x,pd.Series):
        return "pd.Series(%s,dtype='%s',index=pd.%s)" % (list(x),x.dtype,x.index)
    if isinstance(x,pd.DataFrame):
        return "pd.DataFrame({" + ", ".join([
            "'%s': %s" % (c,dput(x[c])) for c in x.columns]) + (
                "}, index=pd.%s)" % (x.index))
    raise NotImplementedError("dput",type(x),x)

今、

df = pd.DataFrame({'a':[1,2,3,4,2,1,3,1]})
assert df.equals(eval(dput(df)))
du = pd.get_dummies(df.a,"foo")
assert du.equals(eval(dput(du)))
di = df
di.index = list('abcdefgh')
assert di.equals(eval(dput(di)))

これは、よりもはるかに詳細な出力を生成することに注意しくださいDataFrame.to_dict。たとえば、

pd.DataFrame({
  'foo_1':pd.Series([1, 0, 0, 0, 0, 1, 0, 1],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_2':pd.Series([0, 1, 0, 0, 1, 0, 0, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_3':pd.Series([0, 0, 1, 0, 0, 0, 1, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_4':pd.Series([0, 0, 0, 1, 0, 0, 0, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1))},
  index=pd.RangeIndex(start=0, stop=8, step=1))

{'foo_1': {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 0, 7: 1}, 
 'foo_2': {0: 0, 1: 1, 2: 0, 3: 0, 4: 1, 5: 0, 6: 0, 7: 0}, 
 'foo_3': {0: 0, 1: 0, 2: 1, 3: 0, 4: 0, 5: 0, 6: 1, 7: 0}, 
 'foo_4': {0: 0, 1: 0, 2: 0, 3: 1, 4: 0, 5: 0, 6: 0, 7: 0}}

以下のためのdu上記の、それは、列の型を保持します。たとえば、上記のテストケースでは、

du.equals(pd.DataFrame(du.to_dict()))
==> False

du.dtypesありuint8pd.DataFrame(du.to_dict()).dtypesですint64


それはより明確ですが、私はなぜそれを使いたいのかわからないことを認めますto_dict
Paul H

2
列タイプを保持するため。具体的には、du.equals(eval(dput(df)))
sds 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.