각 행에서 3번째 NaN 값이 있는 컬럼을 찾아라
import numpy as np
nan = np.nan
data = [[0.04, nan, nan, 0.25, nan, 0.43, 0.71, 0.51, nan, nan],
[ nan, nan, nan, 0.04, 0.76, nan, nan, 0.67, 0.76, 0.16],
[ nan, nan, 0.5 , nan, 0.31, 0.4 , nan, nan, 0.24, 0.01],
[0.49, nan, nan, 0.62, 0.73, 0.26, 0.85, nan, nan, nan],
[ nan, nan, 0.41, nan, 0.05, nan, 0.61, nan, 0.48, 0.68]]
columns = list('abcdefghij')
df = pd.DataFrame(data, columns=columns)
isnull()은 isna()와 같다. isnull은 null 값에 익숙한 사람들을 위해 만든 alias 함수이다.
df.isna().sum() - NaN의 총 개수는 구할 수 있는데 어떻게 3번째일 때를 조건절로 세울까?
cumsum()이라고 누적합을 구해주는 함수가 있다.
df.loc[:, df.isna().cumsum(axis=1) == 3].idxmax()를 실행하면
Cannot index with multidimensional key라는 에러가 뜨는 것을 볼 수 있다.
loc 함수는 행이나 열 자리에 조건을 넣을 때, 1줄짜리(1차원) 조건만을 수용하는데, 실제로 넣은 것은 각 행에 boolean 값이 들어가있는 df와 같은 크기의 2차원 표이기 때문에 에러가 발생한 것이다.
그러면 어떻게 할까??
df.loc을 그냥 안 쓰면 된다.
(df.isna().cumsum(axis=1) == 3).idxmax(axis=1)
여기서 idxmax()??라고 할 수도 있는데, idxmax()는 최댓값이 여러 개가 있으면 가장 먼저 나온 값을 반환한다. 그렇기에 조건절로 max 값을 설정해놓고 가장 맨 첫 번째 값을 출력할 수 있다. 꿀팁이다.
a.b.c 컬럼에서 각각 가장 큰 3개의 값 합 구하시오.
grps
a 409
b 156
c 345
# 내 풀이
df['rank'] = df.groupby(by='grps')['vals'].rank(ascending=False)
df.loc[df['rank']<=3, ['grps','vals']].sort_values(by=['grps']).groupby('grps').sum()
# 해설
df.groupby('grps')['vals'].nlargest(3).sum(level=0)
일단 sort_values를 썼으면 굳이 rank가 없었어도 됐다.

sql을 생각해보면 group by절 사용 후에 특정값을 뽑아내려고 하면 실패하는 경험들이 있을 것이다. 이처럼 pandas에서도 groupby('grps')를 실행하는 순간, 그룹화된 보따리 안에 있다고 생각해야 된다.
.sort_values() 함수는 DataFrame 상태일 때만 사용할 수 있는 전용 함수이기에 그룹화한 후에 정렬을 하려고 하면 정렬 기능 실행 못한다고 에러가 발생되는 것이다!
df['rank']를 선언하고 sort_values를 사용했던 것은 의도가 아니었는데 앞으로는 지식을 가지고 사용하자. 다시 돌아가서!
그룹화한 후에 정렬 못하면 어떻게 하냐? GroupBy 객체 상태에서 상위 N개 추출 전용 함수가 있다.
nlargest라는 함수다.

nlargest(3)을 하고 sum을 하면 그냥 grps가 a,b,c일 때 3번째까지 큰 수를 그냥 다 더한 것 밖에 되지 않는다.
그룹화를 한 것에 주의해야 하는데, 그룹화를 하고 그 안에서 3번째로 큰 수까지 구했다는 건 grps와 vals를 가르는 경계가 있는 것을 생각해볼 수 있다. 이때 밖을 level=0, 안을 level=1이라고 하는데 sum(level=0)이라고 설정하면 레벨 0 기준으로 묶어서 합을 구할 수 있다.
그런데, 에러가 발생할 수도 있어서 요즘은 이렇게 사용하지 않고
df.groupby(by='grps')['vals'].nlargest(3).groupby(level=0).sum()
과 같이 사용한다.
set_flags()
pandas는 컬럼 이름이나 인덱스(행 이름)이 중복되는 것을 허용한다. 다른 사람들이 만든 데이터들을 합칠 때, 다른 의미의 데이터가 이름은 같다면 병합되어 데이터의 가치가 없어질 것이다.
그럴 때, set_flags() 로 중복된 이름표가 들어올 수 없도록 할 수 있다.
df_strict = df.set_flags(allows_duplicate_labels = False)
-> 원래는 덮어씌우거나 추가되지만, 중복 라벨 허용 불가 옵션을 달면 에러가 뜬다.