[python] NaN (결측) 값이있는 pandas GroupBy 열

그룹화하려는 열에 누락 된 값이 많은 DataFrame이 있습니다.

import pandas as pd
import numpy as np
df = pd.DataFrame({'a': ['1', '2', '3'], 'b': ['4', np.NaN, '6']})

In [4]: df.groupby('b').groups
Out[4]: {'4': [0], '6': [2]}

Pandas가 NaN 대상 값으로 행을 삭제했음을 참조하십시오. (이 행을 포함하고 싶습니다!)

많은 연산 (많은 col이 누락 된 값을 가짐)이 필요하고 중간 (일반적으로 임의의 포리스트)보다 복잡한 함수를 사용하기 때문에 너무 복잡한 코드 작성을 피하고 싶습니다.

어떤 제안? 이를 위해 함수를 작성해야합니까 아니면 간단한 해결책이 있습니까?



답변

이것은 문서의 데이터 누락 섹션에 언급되어 있습니다 .

GroupBy의 NA 그룹은 자동으로 제외됩니다. 예를 들어이 동작은 R과 일치합니다.

한 가지 해결 방법은 그룹화를 수행하기 전에 자리 표시자를 사용하는 것입니다 (예 : -1).

In [11]: df.fillna(-1)
Out[11]:
   a   b
0  1   4
1  2  -1
2  3   6

In [12]: df.fillna(-1).groupby('b').sum()
Out[12]:
    a
b
-1  2
4   1
6   3

즉, 이것은 꽤 끔찍한 해킹을 느낍니다. 아마도 NaN을 그룹별로 포함시키는 옵션이 있어야합니다 ( 이 같은 깃 허브 문제 -동일한 자리 표시 자 해킹을 사용합니다).


답변

고대 주제, 누군가 여전히 이것을 우연히 발견하면 다른 해결 방법은 그룹화하기 전에 .astype (str)을 통해 문자열로 변환하는 것입니다. 그것은 NaN을 보존 할 것입니다.

in:
df = pd.DataFrame({'a': ['1', '2', '3'], 'b': ['4', np.NaN, '6']})
df['b'] = df['b'].astype(str)
df.groupby(['b']).sum()
out:
    a
b
4   1
6   3
nan 2


답변

팬더> = 1.1

pandas 1.1 에서이 동작을보다 잘 제어 할 수 있으므로 NA 값은dropna=False 다음을 사용 하여 그룹화에서 허용됩니다 .

pd.__version__
# '1.1.0.dev0+2004.g8d10bfb6f'

# Example from the docs
df

   a    b  c
0  1  2.0  3
1  1  NaN  4
2  2  1.0  3
3  1  2.0  2

# without NA (the default)
df.groupby('b').sum()

     a  c
b
1.0  2  3
2.0  2  5
# with NA
df.groupby('b', dropna=False).sum()

     a  c
b
1.0  2  3
2.0  2  5
NaN  1  4


답변

평판이 충분하지 않기 때문에 M. Kiewisch에 의견을 추가 할 수 없습니다 (41 만 있고 50 명 이상이 필요합니다).

어쨌든 M. Kiewisch 솔루션은 그대로 작동하지 않으며 더 많은 조정이 필요할 수 있음을 지적하고 싶습니다. 예를 들어 고려

>>> df = pd.DataFrame({'a': [1, 2, 3, 5], 'b': [4, np.NaN, 6, 4]})
>>> df
   a    b
0  1  4.0
1  2  NaN
2  3  6.0
3  5  4.0
>>> df.groupby(['b']).sum()
     a
b
4.0  6
6.0  3
>>> df.astype(str).groupby(['b']).sum()
      a
b
4.0  15
6.0   3
nan   2

그룹 b = 4.0의 경우 해당 값은 6 대신 15입니다. 여기서는 숫자로 추가하는 대신 1과 5를 문자열로 연결합니다.


답변

앤디 헤이든의 솔루션을 하나의 작은 점 – 있기 때문에 (? 이상) 작동하지 않습니다 np.nan == np.nan수익률 False, 너무 replace기능이 실제로 아무것도하지 않습니다.

나를 위해 일한 것은 이것이었다 :

df['b'] = df['b'].apply(lambda x: x if not np.isnan(x) else -1)

(적어도 이것이 팬더 0.19.2의 동작입니다. 다른 답변으로 추가하여 죄송합니다. 의견을 말할만한 평판이 없습니다.)


답변

지금까지 제공된 모든 답변은 실제로 데이터 세트의 일부인 더미 값을 선택할 수 있으므로 잠재적으로 위험한 행동을 초래합니다. 많은 속성을 가진 그룹을 만들면 점점 더 커질 것입니다. 간단히 말해서, 접근 방식이 항상 잘 일반화되는 것은 아닙니다.

덜 해킹 된 해결 방법은 pd.drop_duplicates ()를 사용하여 각각 고유 한 ID를 가진 고유 한 값 조합 인덱스를 만든 다음 해당 ID를 그룹화하는 것입니다. 더 장황하지만 작업을 수행합니다.

def safe_groupby(df, group_cols, agg_dict):
    # set name of group col to unique value
    group_id = 'group_id'
    while group_id in df.columns:
        group_id += 'x'
    # get final order of columns
    agg_col_order = (group_cols + list(agg_dict.keys()))
    # create unique index of grouped values
    group_idx = df[group_cols].drop_duplicates()
    group_idx[group_id] = np.arange(group_idx.shape[0])
    # merge unique index on dataframe
    df = df.merge(group_idx, on=group_cols)
    # group dataframe on group id and aggregate values
    df_agg = df.groupby(group_id, as_index=True)\
               .agg(agg_dict)
    # merge grouped value index to results of aggregation
    df_agg = group_idx.set_index(group_id).join(df_agg)
    # rename index
    df_agg.index.name = None
    # return reordered columns
    return df_agg[agg_col_order]

이제 다음을 간단히 수행 할 수 있습니다.

data_block = [np.tile([None, 'A'], 3),
              np.repeat(['B', 'C'], 3),
              [1] * (2 * 3)]

col_names = ['col_a', 'col_b', 'value']

test_df = pd.DataFrame(data_block, index=col_names).T

grouped_df = safe_groupby(test_df, ['col_a', 'col_b'],
                          OrderedDict([('value', 'sum')]))

이렇게하면 더미 값으로 오인 된 실제 데이터를 덮어 쓰지 않아도됩니다.


답변

나는 이것에 이미 대답했지만 어떤 이유로 대답이 주석으로 변환되었습니다. 그럼에도 불구하고 이것이 가장 효율적인 솔루션입니다.

그룹에 NaN을 포함 (및 전파) 할 수없는 것은 상당히 악화되고 있습니다. 이 행동이 다른 많은 것들과 일치하지 않기 때문에 인용 R은 설득력이 없습니다. 어쨌든 더미 핵도 꽤 나쁘다. 그러나 NaN이 있으면 그룹의 크기 (NaN 포함) 및 개수 (NaN 무시)가 달라집니다.

dfgrouped = df.groupby(['b']).a.agg(['sum','size','count'])

dfgrouped['sum'][dfgrouped['size']!=dfgrouped['count']] = None

서로 다른 경우 해당 그룹의 집계 함수 결과에 대해 값을 다시 없음으로 설정할 수 있습니다.