Маска данных соответствует нескольким условиям - PullRequest
0 голосов
/ 18 декабря 2018

Я хотел бы замаскировать (или присвоить 'NA') значение столбца в кадре данных, если выполняются два условия.Это было бы относительно просто, если бы условия выполнялись построчно, с чем-то вроде:

mask = ((df['A'] < x) & (df['B'] < y))
df.loc[mask, 'C'] = 'NA'

, но у меня возникли некоторые затруднения с выяснением того, как выполнить эту задачу в моем фрейме данных, который структурирован болееили меньше, например:

df = pd.DataFrame({ 'A': (188, 750, 1330, 1385, 188, 750, 810, 1330, 1385),
                     'B': (2, 5, 7, 2, 5, 5, 3, 7, 2),
                     'C': ('foo', 'foo', 'foo', 'foo', 'bar', 'bar', 'bar', 'bar', 'bar') })

    A    B C
0   188  2 foo
1   750  5 foo
2   1330 7 foo
3   1385 2 foo
4   188  5 bar
5   750  5 bar
6   810  3 bar
7   1330 7 bar
8   1385 2 bar

Значения в столбце 'A', когда 'C' == 'foo', также должны быть найдены, когда 'C' == 'bar' (что-то вроде индекса), хотя в обоих случаях 'foo' могут отсутствовать данныеи «бар».Как я могу замаскировать (или назначить 'NA') строки столбца 'B', если оба значения 'foo' и 'bar' меньше 5 или отсутствует какой-либо из них?В приведенном выше примере результат будет примерно таким:

    A    B C
0   188  2  foo
1   750  5  foo
2   1330 7  foo
3   1385 NA foo
4   188  5  bar
5   750  5  bar
6   810  NA bar
7   1330 7  bar
8   1385 NA bar

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Другое возможное решение с использованием groupby и некоторых других идей, заимствованных из ответа jpp:

# create a mapping test for each group from column 'A'
fmap = df.groupby(['A']).apply(lambda x: all(x['B'] < 5))
# and generate a new masking map from that
mask_map = df['A'].map(fmap)
# then just mask the values in the original DF
df['B'] = df['B'].mask(mask_map)

      A    B    C
0   188  2.0  foo
1   750  5.0  foo
2  1330  7.0  foo
3  1385  NaN  foo
4   188  5.0  bar
5   750  5.0  bar
6   810  NaN  bar
7  1330  7.0  bar
8  1385  NaN  bar
0 голосов
/ 18 декабря 2018

Вот одно из решений.Идея состоит в том, чтобы создать две логические маски m1 и m2 из двух серий сопоставления s1 и s2.Затем используйте pd.Series.mask для маскирования серии B.

# create separate mappings for foo and bar
s1 = df.loc[df['C'] == 'foo'].set_index('A')['B']
s2 = df.loc[df['C'] == 'bar'].set_index('A')['B']

# use -np.inf to cover missing mappings
m1 = df['A'].map(s1).fillna(-np.inf).lt(5)  
m2 = df['A'].map(s2).fillna(-np.inf).lt(5)

df['B'] = df['B'].mask(m1 & m2)

print(df)

      A    B    C
0   188  2.0  foo
1   750  5.0  foo
2  1330  7.0  foo
3  1385  NaN  foo
4   188  5.0  bar
5   750  5.0  bar
6   810  NaN  bar
7  1330  7.0  bar
8  1385  NaN  bar
...