[python] Pandas : 각 그룹에서 평균으로 결 측값 채우기

이것은 간단해야하지만 내가 찾은 가장 가까운 것은이 게시물입니다 :
pandas : Filling missing values ​​within a group , 그리고 여전히 내 문제를 해결할 수 없습니다 ….

다음 데이터 프레임이 있다고 가정합니다.

df = pd.DataFrame({'value': [1, np.nan, np.nan, 2, 3, 1, 3, np.nan, 3], 'name': ['A','A', 'B','B','B','B', 'C','C','C']})

  name  value
0    A      1
1    A    NaN
2    B    NaN
3    B      2
4    B      3
5    B      1
6    C      3
7    C    NaN
8    C      3

그리고 각 “이름”그룹의 평균 값으로 “NaN”을 채우고 싶습니다. 즉

      name  value
0    A      1
1    A      1
2    B      2
3    B      2
4    B      3
5    B      1
6    C      3
7    C      3
8    C      3

어디로 가야할지 모르겠습니다.

grouped = df.groupby('name').mean()

무리 감사.



답변

한 가지 방법은 다음을 사용하는 것입니다 transform.

>>> df
  name  value
0    A      1
1    A    NaN
2    B    NaN
3    B      2
4    B      3
5    B      1
6    C      3
7    C    NaN
8    C      3
>>> df["value"] = df.groupby("name").transform(lambda x: x.fillna(x.mean()))
>>> df
  name  value
0    A      1
1    A      1
2    B      2
3    B      2
4    B      3
5    B      1
6    C      3
7    C      3
8    C      3


답변

fillna+ groupby+ transform+mean

이것은 직관적 인 것 같습니다.

df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))

그만큼 groupby+의 transform구문은 원래 dataframe의 인덱스에 GroupWise에의 평균을 매핑합니다. 이것은 @DSM의 솔루션 과 거의 동일 하지만 익명 lambda함수 를 정의 할 필요가 없습니다 .


답변

@DSM에는 IMO가 정답이지만 질문에 대한 일반화 및 최적화를 공유하고 싶습니다. 여러 열을 그룹화하고 여러 값 열을 가짐 :

df = pd.DataFrame(
    {
        'category': ['X', 'X', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y'],
        'name': ['A','A', 'B','B','B','B', 'C','C','C'],
        'other_value': [10, np.nan, np.nan, 20, 30, 10, 30, np.nan, 30],
        'value': [1, np.nan, np.nan, 2, 3, 1, 3, np.nan, 3],
    }
)

… 제공합니다 …

  category name  other_value value
0        X    A         10.0   1.0
1        X    A          NaN   NaN
2        X    B          NaN   NaN
3        X    B         20.0   2.0
4        X    B         30.0   3.0
5        X    B         10.0   1.0
6        Y    C         30.0   3.0
7        Y    C          NaN   NaN
8        Y    C         30.0   3.0

이 일반화 경우에 우리에 의해 그룹 싶습니다 category하고 name, 만에 전가value .

다음과 같이 해결할 수 있습니다.

df['value'] = df.groupby(['category', 'name'])['value']\
    .transform(lambda x: x.fillna(x.mean()))

group-by 절의 열 목록을 확인하고 value 바로 뒤에 열 . 이렇게하면 해당 특정 열에서만 변환이 실행됩니다. 끝에 추가 할 수 있지만 모든 열에 대해서만 실행하여 끝에 측정 열을 하나만 제외하고 모두 버립니다. 표준 SQL 쿼리 플래너는이를 최적화 할 수 있었지만 pandas (0.19.2)는이를 수행하지 않는 것 같습니다.

다음을 수행하여 데이터 세트를 늘려 성능 테스트 …

big_df = None
for _ in range(10000):
    if big_df is None:
        big_df = df.copy()
    else:
        big_df = pd.concat([big_df, df])
df = big_df

… 대치 할 필요가없는 열 수에 비례하여 속도가 증가 함을 확인합니다.

import pandas as pd
from datetime import datetime

def generate_data():
    ...

t = datetime.now()
df = generate_data()
df['value'] = df.groupby(['category', 'name'])['value']\
    .transform(lambda x: x.fillna(x.mean()))
print(datetime.now()-t)

# 0:00:00.016012

t = datetime.now()
df = generate_data()
df["value"] = df.groupby(['category', 'name'])\
    .transform(lambda x: x.fillna(x.mean()))['value']
print(datetime.now()-t)

# 0:00:00.030022

마지막 메모에서 모두는 아니지만 둘 이상의 열을 대치하려는 경우 더욱 일반화 할 수 있습니다.

df[['value', 'other_value']] = df.groupby(['category', 'name'])['value', 'other_value']\
    .transform(lambda x: x.fillna(x.mean()))


답변

나는 이런 식으로 할거야

df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean')


답변

위 답변의 대부분은 누락 된 값을 채우기 위해 “groupby”및 “transform”을 사용하는 것과 관련이 있습니다.

그러나 나는 나에게 더 직관적 인 결 측값을 채우기 위해 “apply”와 함께 “groupby”를 사용하는 것을 선호합니다.

>>> df['value']=df.groupby('name')['value'].apply(lambda x:x.fillna(x.mean()))
>>> df.isnull().sum().sum()
    0

지름길: Groupby + Apply / Lambda + Fillna + Mean

이 솔루션은 누락 된 값을 대체하기 위해 여러 열로 그룹화하려는 경우에도 작동합니다.

     >>> df = pd.DataFrame({'value': [1, np.nan, np.nan, 2, 3, np.nan,np.nan, 4, 3],
    'name': ['A','A', 'B','B','B','B', 'C','C','C'],'class':list('ppqqrrsss')})

     >>> df
   value name   class
0    1.0    A     p
1    NaN    A     p
2    NaN    B     q
3    2.0    B     q
4    3.0    B     r
5    NaN    B     r
6    NaN    C     s
7    4.0    C     s
8    3.0    C     s

>>> df['value']=df.groupby(['name','class'])['value'].apply(lambda x:x.fillna(x.mean()))

>>> df
        value name   class
    0    1.0    A     p
    1    1.0    A     p
    2    2.0    B     q
    3    2.0    B     q
    4    3.0    B     r
    5    3.0    B     r
    6    3.5    C     s
    7    4.0    C     s
    8    3.0    C     s


답변

추천 높은 순위 답변은 열이 두 개 뿐인 pandas Dataframe에서만 작동합니다. 더 많은 열이있는 경우 대신 사용하십시오.

df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform(
    lambda x: x.fillna(x.mean()))


답변

def groupMeanValue(group):
    group['value'] = group['value'].fillna(group['value'].mean())
    return group

dft = df.groupby("name").transform(groupMeanValue)