[python] 재현 가능한 팬더 예를 만드는 방법

적절한 시간을 보냈다 그래서 태그에 pandas질문이 재현 가능한 데이터를 포함하지 않을 가능성이 높습니다. 이는 R 커뮤니티 장려에 대해 꽤 잘되었다는 것을, 그리고 같은 가이드 덕분에 , 이민자 함께이 예제를 퍼팅에 대한 몇 가지 도움을받을 수 있습니다. 이 안내서를 읽고 재현 가능한 데이터를 다시 얻을 수있는 사람들은 종종 질문에 대한 답변을 얻는 것이 훨씬 더 좋습니다.

pandas질문 에 대한 좋은 재현 가능한 예를 어떻게 만들 수 있습니까? 다음과 같은 간단한 데이터 프레임을 구성 할 수 있습니다.

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

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

  • datetime 지수 또는 데이터
  • 여러 범주 형 변수 ( expand.grid()주어진 변수의 모든 가능한 조합을 생성 하는 R의 함수 와 동등한가 ?)
  • 다중 인덱스 또는 패널 데이터

몇 줄의 코드를 사용하여 조롱하기 어려운 데이터 세트의 경우 데이터 dput()구조를 재생성하기 위해 복사하여 붙여 넣을 수있는 코드를 생성 할 수있는 R 과 동등한가?



답변

참고 : 여기의 아이디어는 실제로 스택 오버플로에 대한 일반적인 질문 입니다.

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

좋은 점 :

  • 실행 가능한 코드로 작은 * 예제 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 사용 )에서 생성해야합니다 (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의 검색을 ), 요약을 제공합니다 :

    합계에 대한 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
    

    올바른 방법은 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+ ??) 줄의 데이터를 포함시키지 마십시오.

    우리는 우리의 일상 생활에서 이것을 충분히 볼 수 있습니다. 우리는하지만, 도움말을 원하는 하지 이런 … .
    소개를 잘라 내고 문제를 일으키는 단계에서 관련 DataFrame (또는 작은 버전)을 표시하십시오.

어쨌든 Python, NumPy 및 Pandas를 배우는 재미가 있습니다!


답변

샘플 데이터 세트를 생성하는 방법

이것은 주로 샘플 데이터 프레임을 만드는 방법에 대한 예제를 제공하여 @AndyHayden의 답변을 확장하는 것입니다. 팬더 및 (특히) numpy는 몇 줄의 코드로 일반적으로 실제 데이터 세트의 합리적인 팩시밀리를 만들 수 있도록 다양한 도구를 제공합니다.

숫자와 팬더를 가져온 후 사람들이 데이터와 결과를 정확하게 재현 할 수있게하려면 임의의 시드를 제공해야합니다.

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


답변

답변자 일기

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

동기 부여

여러 가지 이유로 질문에 대답하려고합니다.

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

나의 가장 순수한 의도는 모두 위대하고 모든 것이지만, 한 질문 또는 30 개의 질문에 대답하면 그 만족도를 얻습니다. 어떤 질문에 대답 할 수있는 선택이끌어 내는가 포인트 극대화의 큰 요소를 가지고 있습니다.

나는 또한 흥미로운 문제에 시간을 할애하지만 그 사이에는별로 없으며 관심이없는 질문에 대한 해결책이 필요한 질문을하는 사람에게는 도움이되지 않습니다. 내가 질문에 대답하게하는 최선의 방법은 가능한 적은 노력으로 그 질문에 답할 수 있도록 잘 익은 플래터에 그 질문을 제공하는 것입니다. 두 가지 질문을보고 있고 하나는 코드가있는 경우 붙여 넣기를 복사하여 필요한 모든 변수를 만들 수 있습니다 … 그중 하나를 취하고 있습니다! 시간이 있으면 다른 곳으로 다시 올게요

주요 조언

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

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

당신의 명성은 단순한 명성 이상의 것입니다.

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


어쨌든, 아마도 갈 수는 있지만 실제로 이것을 읽는 당신을 모두 구할 것입니다.


답변

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

좋은 팬더 질문을 작성하기 위해 @Andy가 제공하는 지침은 시작하기에 좋은 장소입니다. 자세한 정보 는 요청 방법 및 최소, 완료 및 검증 가능한 예제 작성 방법을 참조하십시오 .

질문을 명확하게 진술하십시오. 질문과 샘플 코드를 작성하는 데 시간이 걸리면 질문을 읽고 독자에게 문제를 요약하고 명확하게 설명하는 ‘실행 요약’을 제공하십시오.

원래 질문 :

이 데이터가 있습니다 …

나는 이것을하고 싶다 …

내 결과가 다음과 같이 보이기를 원합니다 …

그러나 [this]를 시도하면 다음과 같은 문제가 발생합니다.

나는 [this]와 [that]을함으로써 해결책을 찾으려고 노력했다.

어떻게 고치나요?

제공된 데이터 양, 샘플 코드 및 오류 스택에 따라 독자는 문제가 무엇인지 이해하기 전에 먼 길을 가야합니다. 질문 자체가 맨 위에 오도록 질문을 정리 한 다음 필요한 세부 사항을 제공하십시오.

수정 된 질문 :

인용 : 어떻게해야합니까?

나는 [this]와 [that]을함으로써 해결책을 찾으려고 노력했다.

[이것]을 시도하면 다음과 같은 문제가 발생합니다.

최종 결과는 다음과 같습니다.

내 문제를 재현 할 수있는 최소한의 코드가 있습니다 …

다음은 샘플 데이터를 재생성하는 방법입니다.
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에 대한 설명을 제공 할 수도 있습니다. 이를 통해 다른 사람들이 각 열의 데이터 유형을 확인하고 다른 일반적인 오류 (예 : 날짜를 문자열 대 날짜 / 시간 64 대 개체)를 식별 할 수 있습니다.

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


답변

다음은 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))

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

위해 du위,하지만 열 유형을 유지 . 예를 들어, 위 테스트 사례에서

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

때문에이 du.dtypes있다 uint8하고 pd.DataFrame(du.to_dict()).dtypes있다 int64.


답변


댓글 달기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다