Панды считают разные комбинации 2 колонок с нан - PullRequest
4 голосов
/ 01 апреля 2019

У меня есть датафрейм, похожий на

df = pd.DataFrame({'A': [1, np.nan,2,3, np.nan,4], 'B': [np.nan, 1,np.nan,2, 3, np.nan]})
df
     A    B
0  1.0  NaN
1  NaN  1.0
2  2.0  NaN
3  3.0  2.0
4  NaN  3.0
5  4.0  NaN

Как рассчитать количество вхождений A: np.nan, но B не np.nan, A не np.nan, а B = np.nan, а A и B оба не np.nan?

Я пытался df.groupby(['A', 'B']).count(), но он не читает строки с np.nan.

Ответы [ 5 ]

6 голосов
/ 01 апреля 2019

Если мы имеем дело только с двумя столбцами, есть очень простое решение, которое заключается в назначении простых весов столбцам A и B, а затем их суммировании.

v = df.isna().mul([1, 2]).sum(1).value_counts() 
v.index = v.index.map({2: 'only B', 1: 'only A', 0: 'neither'})    
v

only B     3
only A     2
neither    1
dtype: int64

Еще одна альтернатива с pivot_table и stack может быть достигнута,

df.isna().pivot_table(index='A', columns='B', aggfunc='size').stack()

A      B    
False  False    1.0
       True     3.0
True   False    2.0
dtype: float64
6 голосов
/ 01 апреля 2019

Использование

df.isnull().groupby(['A','B']).size()
Out[541]: 
A      B    
False  False    1
       True     3
True   False    2
dtype: int64
5 голосов
/ 01 апреля 2019

Вы можете использовать DataFrame.isna с crosstab для значений Trues:

df1 = df.isna()
df2 = pd.crosstab(df1.A, df1.B)
print (df2)
B      False  True 
A                  
False      1      3
True       2      0

Для скаляра:

print (df2.loc[False, False])
1

df2 = pd.crosstab(df1.A, df1.B).add_prefix('B_').rename(lambda x: 'A_' + str(x))
print (df2)
B        B_False  B_True
A                       
A_False        1       3
A_True         2       0

Тогда для скалярного индексирования используйте:

print (df2.loc['A_False', 'B_False'])
1

Другое решение заключается в использовании DataFrame.dot именами столбцов с Series.replace и Series.value_counts:

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

s = df.isna().dot(df.columns).replace({'':'no match'}).value_counts()
print (s)

B           3
A           2
no match    1
AB          1
dtype: int64
1 голос
/ 01 апреля 2019

Я думаю, вам нужно:

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

count1 = len(df[(~df['A'].isnull()) & (df['B'].isnull())])
count2 = len(df[(~df['A'].isnull()) & (~df['B'].isnull())])
count3 = len(df[(df['A'].isnull()) & (~df['B'].isnull())])

print(count1, count2, count3)

Выход:

3 1 2
0 голосов
/ 01 апреля 2019

Чтобы получить строки, в которых либо A, либо B являются нулевыми, мы можем сделать:

bool_df = df.isnull()
df[bool_df['A'] ^ bool_df['B']].shape[0]

Чтобы получить строки, в которых оба имеют нулевые значения:

df[bool_df['A'] & bool_df['B']].shape[0]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...