source

Python Pandas 연산 결과를 상위 데이터 프레임의 열에 다시 할당하는 방법은 무엇입니까?

nicesource 2023. 9. 21. 20:35
반응형

Python Pandas 연산 결과를 상위 데이터 프레임의 열에 다시 할당하는 방법은 무엇입니까?

IPython에는 다음과 같은 데이터 프레임이 있습니다. 각 행은 하나의 스톡입니다.

In [261]: bdata
Out[261]:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 21210 entries, 0 to 21209
Data columns:
BloombergTicker      21206  non-null values
Company              21210  non-null values
Country              21210  non-null values
MarketCap            21210  non-null values
PriceReturn          21210  non-null values
SEDOL                21210  non-null values
yearmonth            21210  non-null values
dtypes: float64(2), int64(1), object(4)

"년월" 열의 각 날짜마다 모든 항목에 걸쳐 상한 가중치 평균 수익률을 계산하는 작업별 그룹을 적용하고자 합니다.

예상대로 작동합니다.

In [262]: bdata.groupby("yearmonth").apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
Out[262]:
yearmonth
201204      -0.109444
201205      -0.290546

그런 다음 이 값들을 원래 데이터 프레임의 인덱스로 다시 "브로드캐스트"한 다음 날짜가 일치하는 일정한 열로 저장하고자 합니다.

In [263]: dateGrps = bdata.groupby("yearmonth")

In [264]: dateGrps["MarketReturn"] = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/mnt/bos-devrnd04/usr6/home/espears/ws/Research/Projects/python-util/src/util/<ipython-input-264-4a68c8782426> in <module>()
----> 1 dateGrps["MarketReturn"] = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())

TypeError: 'DataFrameGroupBy' object does not support item assignment

저는 이 순진한 과제가 효과가 있어서는 안 된다는 것을 알고 있습니다.그러나 조작에 의한 그룹의 결과를 상위 데이터 프레임의 새 열에 할당하는 "올바른" 판다 관용어는 무엇일까요?

결국 연산별 그룹의 출력과 날짜가 일치하는 모든 지수에 대해 반복되는 상수 값이 되는 "MarketReturn"이라는 열을 원합니다.

이를 달성하기 위한 한 번의 해킹은 다음과 같습니다.

marketRetsByDate  = dateGrps.apply(lambda x: (x["PriceReturn"]*x["MarketCap"]/x["MarketCap"].sum()).sum())

bdata["MarketReturn"] = np.repeat(np.NaN, len(bdata))

for elem in marketRetsByDate.index.values:
    bdata["MarketReturn"][bdata["yearmonth"]==elem] = marketRetsByDate.ix[elem]

하지만 이것은 느리고 나쁘고 파이토닉적이지 않습니다.

In [97]: df = pandas.DataFrame({'month': np.random.randint(0,11, 100), 'A': np.random.randn(100), 'B': np.random.randn(100)})

In [98]: df.join(df.groupby('month')['A'].sum(), on='month', rsuffix='_r')
Out[98]:
           A         B  month       A_r
0  -0.040710  0.182269      0 -0.331816
1  -0.004867  0.642243      1  2.448232
2  -0.162191  0.442338      4  2.045909
3  -0.979875  1.367018      5 -2.736399
4  -1.126198  0.338946      5 -2.736399
5  -0.992209 -1.343258      1  2.448232
6  -1.450310  0.021290      0 -0.331816
7  -0.675345 -1.359915      9  2.722156

내가 아직도 엄청나게 똑똑한 방법을 연구하는 동안apply지정된 조각을 연결합니다. 다음은 작업별 그룹 후 상위에 새 열을 추가하는 다른 방법입니다.

In [236]: df
Out[236]: 
  yearmonth    return
0    201202  0.922132
1    201202  0.220270
2    201202  0.228856
3    201203  0.277170
4    201203  0.747347

In [237]: def add_mkt_return(grp):
   .....:     grp['mkt_return'] = grp['return'].sum()
   .....:     return grp
   .....: 

In [238]: df.groupby('yearmonth').apply(add_mkt_return)
Out[238]: 
  yearmonth    return  mkt_return
0    201202  0.922132    1.371258
1    201202  0.220270    1.371258
2    201202  0.228856    1.371258
3    201203  0.277170    1.024516
4    201203  0.747347    1.024516

일반적으로 groupby()를 사용할 때 .transform() 함수 panda를 사용하면 원래와 같은 길이의 테이블이 반환됩니다..sum() 또는 .first()와 같은 다른 함수를 사용하면 각 행이 그룹인 테이블이 반환됩니다.

이것이 어떻게 적용되는지는 잘 모르겠지만 정교한 람다 함수를 변환으로 구현하는 것은 상당히 까다로울 수 있기 때문에 가장 도움이 되는 전략은 필요한 변수를 생성하고 원래 데이터 세트에 배치한 다음 작업을 수행하는 것입니다.

먼저 올바르게 수행하려는 작업을 이해하면 각 그룹의 총 시가총액을 계산할 수 있습니다.

bdata['group_MarketCap'] = bdata.groupby('yearmonth')['MarketCap'].transform('sum')

이렇게 하면 각 그룹별 시가총액의 합계를 포함하는 원래 데이터에 "group_MarketCap"이라는 열이 추가됩니다.그런 다음 가중치를 직접 계산할 수 있습니다.

bdata['weighted_P'] = bdata['PriceReturn'] * (bdata['MarketCap']/bdata['group_MarketCap'])

그리고 마지막으로 동일한 변환 함수를 사용하여 각 그룹에 대한 가중 평균을 계산합니다.

bdata['MarketReturn'] = bdata.groupby('yearmonth')['weighted_P'].transform('sum')

저는 변수를 이런 식으로 만드는 경향이 있습니다.때로는 하나의 명령어로 모든 것을 처리할 수 있지만, 대부분의 경우 팬더가 전체 데이터 세트 스케일에서 작동하려면 새 개체를 인스턴스화해야 하기 때문에(즉, 하나가 아직 존재하지 않으면 두 개의 열을 함께 추가할 수 없음) groupby()에서 항상 작동하지는 않습니다.

도움이 되길 바라요 :)

요를 ?transform메소드(대신 aggregate)?원래 예에서 사용한다면 원하는 대로 (방송) 할 수 있습니다.

원래 데이터 프레임에 할당할 방법을 찾지 못했습니다.그래서 저는 그룹의 결과를 저장하고 연결합니다.그런 다음 연결된 데이터 프레임을 인덱스별로 정렬하여 원래 순서를 입력 데이터 프레임으로 얻습니다.다음은 샘플 코드입니다.

In [10]: df = pd.DataFrame({'month': np.random.randint(0,11, 100), 'A': np.random.randn(100), 'B': np.random.randn(100)})

In [11]: df.head()
Out[11]:
   month         A         B
0      4 -0.029106 -0.904648
1      2 -2.724073  0.492751
2      7  0.732403  0.689530
3      2  0.487685 -1.017337
4      1  1.160858 -0.025232

In [12]: res = []

In [13]: for month, group in df.groupby('month'):
    ...:     new_df = pd.DataFrame({
    ...:         'A^2+B': group.A ** 2 + group.B,
    ...:         'A+B^2': group.A + group.B**2
    ...:     })
    ...:     res.append(new_df)
    ...:

In [14]: res = pd.concat(res).sort_index()

In [15]: res.head()
Out[15]:
      A^2+B     A+B^2
0 -0.903801  0.789282
1  7.913327 -2.481270
2  1.225944  1.207855
3 -0.779501  1.522660
4  1.322360  1.161495

이 방법은 상당히 빠르고 확장 가능합니다.여기서 모든 특징을 도출할 수 있습니다.

참고: 데이터 프레임이 너무 크면,concatMMO 오류를 유발할 수 있습니다.

언급URL : https://stackoverflow.com/questions/12200693/python-pandas-how-to-assign-groupby-operation-results-back-to-columns-in-parent

반응형