재현 가능한 판다 예제를 만드는 방법

Nov 21 2013

SO 에서 r 및 pandas 태그를 모두 시청하는 데 상당한 시간을 투자 한 결과 , pandas질문에 재현 가능한 데이터가 포함될 가능성이 적다 는 인상을 받았습니다 . 이것은 R 커뮤니티가 격려하는 데 꽤 좋은 것입니다. 이와 같은 가이드 덕분에 신규 이민자는 이러한 예제를 작성하는 데 도움을 얻을 수 있습니다. 이 가이드를 읽고 재현 가능한 데이터를 가지고 돌아올 수있는 사람들은 종종 질문에 대한 답을 얻는 데 훨씬 더 좋은 행운을 가질 것입니다.

pandas질문 에 대해 재현 가능한 좋은 예를 어떻게 만들 수 있습니까? 간단한 데이터 프레임을 함께 사용할 수 있습니다. 예 :

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

그러나 많은 예제 데이터 세트에는 더 복잡한 구조가 필요합니다. 예 :

  • datetime 인덱스 또는 데이터
  • 여러 범주 형 변수 ( expand.grid()주어진 변수의 모든 가능한 조합을 생성 하는 R의 함수 와 동일한 기능이 있습니까?)
  • MultiIndex 또는 Panel 데이터

몇 줄의 코드를 사용하여 모의하기 어려운 데이터 세트의 경우 dput()복사하여 붙여 넣을 수있는 코드를 생성하여 데이터 구조를 다시 생성 할 수있는 R에 해당하는 것이 있습니까?

답변

362 AndyHayden Nov 23 2013 at 13:19

참고 : 여기에 아이디어를 실제로 스택 오버플로 꽤 일반적이다 질문 .

면책 조항 : 좋은 질문을 작성하는 것은 어렵습니다.

장점 :

  • 실행 가능한 코드로 작은 * 예제 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+')자신을 테스트 하십시오.

    * 정말 뜻 작은이 , 예를 들어 DataFrames의 대부분이 될 수보다 적은 6 행은 표창장은 필요로 하고, 나는 5 행에 그것을 할 수 내기. df = df.head()당신이 직면하고있는 문제를 나타내는 작은 DataFrame을 구성 할 수 있는지 확인하기 위해 주위를 둘러 보지 않는 경우 오류를 재현 할 수 있습니까?

    * 모든 규칙에는 예외가 있습니다. 명백한 것은 성능 문제에 대한 것입니다 ( 이 경우 확실히 % timeit 및 가능하면 % prun 사용 ). 여기서 생성해야합니다 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에 대한 독 스트링은 단순히 "그룹 값의 합계 계산"이라고 말합니다.

    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를 포함하지 마십시오 . 이것은 pandas 기본 디스플레이에 대한 일종의 불만이지만 그럼에도 불구하고 성가신 것입니다.

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

    올바른 방법은 set_index호출에 일반 DataFrame을 포함하는 것입니다 .

    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+ ??) 줄의 데이터를 포함하지 마십시오.

    제발, 우리는 우리의 일상 업무에서 이것을 충분히 봅니다. 우리는하지만, 도움말을 원하는 하지 이런 ... .
    인트로를 잘라 내고 문제를 일으키는 단계에서 관련 DataFrames (또는 그 작은 버전) 만 표시합니다.

어쨌든 Python, NumPy 및 Pandas를 재미있게 배우십시오!

77 JohnE May 24 2015 at 21:22

샘플 데이터 세트를 만드는 방법

이것은 주로 샘플 데이터 프레임을 만드는 방법에 대한 예제를 제공하여 @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.repeatnp.tile(열 de)은 매우 규칙적인 방식으로 그룹과 인덱스를 만드는 데 매우 유용합니다. 2 개 열의 경우 r을 쉽게 복제하는 데 사용할 수 expand.grid()있지만 모든 순열의 하위 집합을 제공하는 기능이 더 유연합니다. 그러나 3 개 이상의 열의 경우 구문이 빠르게 다루기 어려워집니다.
  2. 연구의의를위한보다 직접적인 교환에 대해서는 expand.grid()투시 itertools의 솔루션 팬더가 요리 책 이나 np.meshgrid솔루션이 표시 여기 . 그들은 모든 차원을 허용합니다.
  3. 당신은 np.random.choice. 예를 들어, 열에 g는 2011 년부터 6 개 날짜를 무작위로 선택했습니다. 또한 설정 replace=False을 통해 이러한 날짜가 고유한지 확인할 수 있습니다.이 날짜를 고유 한 값이있는 인덱스로 사용하려는 경우 매우 편리합니다.

가짜 주식 시장 데이터

위 코드의 하위 집합을 취하는 것 외에도 기술을 추가로 결합하여 거의 모든 작업을 수행 할 수 있습니다. 예를 들어, 다음 은 동일한 날짜를 포함하는 4 개의 주식에 대한 샘플 티커 데이터를 결합 np.tile하고 date_range생성 하는 간단한 예입니다 .

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
51 piRSquared Jul 20 2016 at 01:35

답변자의 일기

질문을 할 때 가장 좋은 조언은 질문에 대답하는 사람들의 심리학을 활용하는 것입니다. 그런 사람들 중 하나이기 때문에 내가 특정 질문에 대답하는 이유와 다른 사람에게 대답하지 않는 이유에 대한 통찰력을 줄 수 있습니다.

동기

나는 여러 가지 이유로 질문에 답하고자하는 동기가있다

  1. Stackoverflow.com은 저에게 매우 귀중한 리소스였습니다. 나는 돌려주고 싶었다.
  2. 되돌려 주려고 노력하면서이 사이트가 이전보다 훨씬 더 강력한 리소스임을 알게되었습니다. 질문에 답하는 것은 저에게 학습 경험이며 배우고 싶습니다. 이 답변과 다른 수의사의 의견을 읽으십시오 . 이런 상호 작용은 저를 행복하게합니다.
  3. 나는 포인트를 좋아한다!
  4. # 3을 참조하십시오.
  5. 나는 흥미로운 문제를 좋아합니다.

나의 가장 순수한 의도는 모두 훌륭하지만 1 개 또는 30 개 질문에 답하면 만족을 얻습니다. 답할 질문에 대한 선택유도 하는 요인은 포인트 극대화의 큰 요소입니다.

나는 또한 흥미로운 문제들에 시간을 할애 할 것이지만, 그것은 매우 드물고 흥미롭지 않은 질문에 대한 해결책이 필요한 질문자에게 도움이되지 않습니다. 제가 질문에 대답하도록하는 가장 좋은 방법은 가능한 한 적은 노력으로 대답 할 수 있도록 잘 익은 접시에 그 질문을 담는 것입니다. 두 가지 질문을보고 있고 하나에 코드가있는 경우 붙여 넣기를 복사하여 필요한 모든 변수를 만들 수 있습니다. 시간이 있으면 다른 곳으로 돌아 올게요.

주요 조언

사람들이 질문에 쉽게 답할 수 있도록하십시오.

  • 필요한 변수를 생성하는 코드를 제공합니다.
  • 해당 코드를 최소화하십시오. 게시물을 보며 눈이 반짝이면 다음 질문으로 넘어가거나 내가하고있는 다른 일로 돌아갑니다.
  • 당신이 요구하는 것을 생각하고 구체적으로 말하십시오. 자연어 (영어)가 정확하지 않고 헷갈 리기 때문에 우리는 당신이 한 일을보고 싶습니다. 시도한 코드 샘플은 자연어 설명의 불일치를 해결하는 데 도움이됩니다.
  • 기대하는 것을 보여주세요 !!! 나는 앉아서 뭔가를 시도해야합니다. 나는 어떤 것을 시도하지 않고는 질문에 대한 답을 거의 알지 못한다. 당신이 찾고있는 것에 대한 예가 없다면, 추측하고 싶지 않아서 질문을 전달할 수 있습니다.

당신의 평판은 당신의 평판 그 이상입니다.

나는 포인트를 좋아한다 (위에서 언급했다). 하지만 그 점은 제 평판이 아닙니다. 저의 진정한 평판은 사이트의 다른 사람들이 저에 대해 생각하는 것의 융합입니다. 나는 공정하고 정직하기 위해 노력하며 다른 사람들이 그것을 볼 수 있기를 바랍니다. 그것이 질문자에게 의미하는 것은 우리는 질문자의 행동을 기억한다는 것입니다. 답변을 선택하지 않고 좋은 답변을 찬성하지 않으면 기억합니다. 내가 좋아하지 않는 방식으로 행동하거나 내가 좋아하는 방식으로 행동한다면 기억합니다. 이것은 또한 내가 대답 할 질문에 적용됩니다.


어쨌든 나는 계속할 수 있지만 실제로 이것을 읽는 여러분 모두를 아끼지 않을 것입니다.

31 Alexander Sep 12 2015 at 14:06

과제 SO 질문에 응답하는 데있어 가장 어려운 측면 중 하나는 문제 (데이터 포함)를 재현하는 데 걸리는 시간입니다. 데이터를 재현 할 수있는 명확한 방법이없는 질문은 대답 할 가능성이 적습니다. 질문을 작성하는 데 시간을 할애하고 도움이 필요한 문제가있는 경우 다른 사람이 문제 해결에 사용할 수있는 데이터를 제공하여 쉽게 자신을 도울 수 있습니다.

좋은 Pandas 질문을 작성하기 위해 @Andy가 제공하는 지침은 시작하기에 좋은 곳입니다. 자세한 내용 은 요청 방법 및 최소, 완전 및 검증 가능한 예제 를 만드는 방법을 참조하십시오 .

질문을 미리 명확하게 말씀해주십시오. 질문과 샘플 코드를 작성하는 데 시간을 할애 한 후, 그것을 읽고 독자에게 문제를 요약하고 질문을 명확하게 설명하는 'Executive Summary'를 제공하십시오.

Original question:

I have this data...

I want to do this...

I want my result to look like this...

However, when I try to do [this], I get the following problem...

I've tried to find solutions by doing [this] and [that].

How do I fix it?

Depending on the amount of data, sample code and error stacks provided, the reader needs to go a long way before understanding what the problem is. Try restating your question so that the question itself is on top, and then provide the necessary details.

Revised Question:

Qustion: How can I do [this]?

I've tried to find solutions by doing [this] and [that].

When I've tried to do [this], I get the following problem...

I'd like my final results to look like this...

Here is some minimal code that can reproduce my problem...

And here is how to recreate my sample data: df = pd.DataFrame({'A': [...], 'B': [...], ...})

PROVIDE SAMPLE DATA IF NEEDED!!!

Sometimes just the head or tail of the DataFrame is all that is needed. You can also use the methods proposed by @JohnE to create larger datasets that can be reproduced by others. Using his example to generate a 100 row DataFrame of stock prices:

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) })

If this was your actual data, you may just want to include the head and/or tail of the dataframe as follows (be sure to anonymize any sensitive data):

>>> 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'}}

You may also want to provide a description of the DataFrame (using only the relevant columns). This makes it easier for others to check the data types of each column and identify other common errors (e.g. dates as string vs. datetime64 vs. object):

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)

NOTE: If your DataFrame has a MultiIndex:

If your DataFrame has a multiindex, you must first reset before calling to_dict. You then need to recreate the index using 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
15 sds Dec 17 2016 at 00:57

Here is my version of dput - the standard R tool to produce reproducible reports - for Pandas DataFrames. It will probably fail for more complex frames, but it seems to do the job in simple cases:

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)

now,

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)))

Note that this produces a much more verbose output than DataFrame.to_dict, e.g.,

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))

vs

{'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}}

for du above, but it preserves column types. E.g., in the above test case,

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

because du.dtypes is uint8 and pd.DataFrame(du.to_dict()).dtypes is int64.