판다: 각 그룹의 평균으로 결측치 채우기
이것은 간단해야 하지만, 제가 발견한 가장 가까운 것은 이 게시물입니다: 팬더: 그룹 내에서 누락된 값을 채워도 여전히 문제를 해결할 수 없습니다.
다음과 같은 데이터 프레임이 있다고 가정합니다.
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구문은 그룹별 평균을 원래 데이터 프레임의 인덱스에 매핑합니다.이는 @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()))
의 열 하고인 합니다를 합니다.value그룹 바이 바로 뒤에 난이 있습니다.이렇게 하면 해당 열에서만 변환이 실행됩니다.끝에 추가할 수 있지만, 마지막에 측정 열 하나를 제외한 모든 열에 대해서만 추가할 수 있습니다.표준 SQL 쿼리 계획자는 이 작업을 최적화할 수 있었지만 panda(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['value1']=df.groupby('name')['value'].apply(lambda x:x.fillna(x.mean()))
>>> df.isnull().sum().sum()
0
결측값을 바꾸기 위해 여러 열로 그룹화하려는 경우에도 이 솔루션은 여전히 작동합니다.
>>> 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']=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
이런 식으로 하겠습니다.
df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean')
특징적인 높은 순위의 답변은 두 개의 열만 있는 판다 데이터 프레임에만 적용됩니다.더 많은 열이 있는 경우 대신 다음을 사용합니다.
df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform(
lambda x: x.fillna(x.mean()))
가능한 솔루션의 효율성과 관련하여 위의 모든 내용을 요약하자면, 97906개의 행과 48개의 열을 가진 데이터 세트를 가지고 있습니다.각 그룹의 중앙값으로 4개의 열을 채우고 싶습니다.제가 그룹화하고 싶은 열은 26개의 200개 그룹이 있습니다.
첫번째 해결책은
start = time.time()
x = df_merged[continuous_variables].fillna(df_merged.groupby('domain_userid')[continuous_variables].transform('median'))
print(time.time() - start)
0.10429811477661133 seconds
두번째 해결책은
start = time.time()
for col in continuous_variables:
df_merged.loc[df_merged[col].isnull(), col] = df_merged.groupby('domain_userid')[col].transform('median')
print(time.time() - start)
0.5098445415496826 seconds
다음 솔루션은 너무 오래 실행되었기 때문에 서브셋에서만 수행했습니다.
start = time.time()
for col in continuous_variables:
x = df_merged.head(10000).groupby('domain_userid')[col].transform(lambda x: x.fillna(x.median()))
print(time.time() - start)
11.685635566711426 seconds
다음 솔루션은 위와 같은 논리를 따릅니다.
start = time.time()
x = df_merged.head(10000).groupby('domain_userid')[continuous_variables].transform(lambda x: x.fillna(x.median()))
print(time.time() - start)
42.630549907684326 seconds
따라서 올바른 방법을 선택하는 것이 매우 중요합니다.열이 숫자가 아닌 경우 시간이 기하급수적으로 증가하고 있음을 알게 되었습니다(중앙값을 계산할 때 의미가 있음).
def groupMeanValue(group):
group['value'] = group['value'].fillna(group['value'].mean())
return group
dft = df.groupby("name").transform(groupMeanValue)
그것이 오래된 질문이라는 것을 압니다.하지만 나는 그들의 만장일치에 매우 놀랍니다.apply/lambda여기에 답이 있습니다.
일반적으로 말하면, 시점의 관점에서 행을 반복한 다음에 두 번째로 나쁜 일입니다.
여기서 제가 할 일은.
df.loc[df['value'].isna(), 'value'] = df.groupby('name')['value'].transform('mean')
또는 필나를 사용합니다.
df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))
시간을 두고 확인했습니다. (다시 한 번, apply/lambda 기반 솔루션에 대한 만장일치로 본능이 의심스러웠기 때문입니다.)그리고 이는 가장 많은 지지를 받은 솔루션보다 실제로 2.5배나 빠릅니다.
모든 숫자 null 값을 "이름"으로 그룹화된 평균으로 채우는 방법
num_cols = df.select_dtypes(exclude='object').columns
df[num_cols] = df.groupby("name").transform(lambda x: x.fillna(x.mean()))
df.fillna(df.groupby(['name'], as_index=False).mean(), inplace=True)
사용할 수도 있습니다."dataframe or table_name".apply(lambda x: x.fillna(x.mean())).
언급URL : https://stackoverflow.com/questions/19966018/pandas-filling-missing-values-by-mean-in-each-group
'programing' 카테고리의 다른 글
| printf()가 있는 문자열 중심 맞추기 (0) | 2023.10.09 |
|---|---|
| 아무것도 하지 않기 위해 잠시 블록을 사용하는 것은 나쁜 일입니까? (0) | 2023.10.09 |
| 워드 프레스 헤더 탐색 목록 항목을 div로 변경 (0) | 2023.10.09 |
| SQL행반납순서 (0) | 2023.10.09 |
| 자바스크립트에서 숫자의 소수점 수를 구하는 가장 간단한 방법 (0) | 2023.10.09 |