изменить столбец в предварительно выбранных элементах в панде - PullRequest
0 голосов
/ 09 сентября 2018

У нас есть фрейм данных с тремя разными столбцами, как показано в примере выше ( df ). Цель этой задачи - заменить первый элемент столбца 2 на np.nan при каждом изменении буквы в столбце 1 . Поскольку исследуемая база данных очень большая, ее нельзя использовать для цикла for. Также исключается любое решение, включающее сдвиг, потому что оно слишком медленное

Я считаю, что самый простой способ - это использовать groupby и head метод, однако я не знаю, как заменить в исходном фрейме данных.

Примеры:

df = pd.DataFrame([['A','Z',1.11],['B','Z',2.1],['C','Z',3.1],['D', 'X', 2.1], ['E','X',4.3],['E', 'X', 2.1], ['F','X',4.3]])

enter image description here

чтобы выбрать элементы, которые мы хотим изменить, мы можем сделать следующее:

df.groupby(by=1).head(1)[2] = np.nan

Однако в исходном кадре данных ничего не меняется.
Цель состоит в том, чтобы получить следующее:

enter image description here

Edit:

Исходя из комментариев, мы не будем df[1] возвращаться в группу, которую уже видели, например, ['Z', 'Z', 'X', 'Z'] невозможно.

Ответы [ 5 ]

0 голосов
/ 09 сентября 2018

Создан для скорости

a = df[1].values
b = np.flatnonzero(np.append(True, a[1:] != a[:-1]))
df[2].values[b] = np.nan

df

   0  1    2
0  A  Z  NaN
1  B  Z  2.1
2  C  Z  3.1
3  D  X  NaN
4  E  X  4.3
5  E  X  2.1
6  F  X  4.3
0 голосов
/ 09 сентября 2018

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

df[2].mask(df.groupby(1).cumcount().eq(0))
Out[41]: 
0    NaN
1    2.1
2    3.1
3    NaN
4    4.3
5    2.1
6    4.3
Name: 2, dtype: float64

#df[2] = df[2].mask(df.groupby(1).cumcount().eq(0))
0 голосов
/ 09 сентября 2018

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

df[2] = df[2].mask(df[1].ne(df[1].shift(1)))

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

df[2] = np.ma.masked_array(df[2], df[1].ne(df[1].shift(1))).filled(np.nan)
# array([nan, 2.1, 3.1, nan, 4.3, 2.1, 4.3])

Использование np.roll и loc:

a = df[1].values
df.loc[np.roll(a, 1)!=a, 2] = np.nan

   0  1    2
0  A  Z  NaN
1  B  Z  2.1
2  C  Z  3.1
3  D  X  NaN
4  E  X  4.3
5  E  X  2.1
6  F  X  4.3
0 голосов
/ 09 сентября 2018

Вы можете использовать numpy.where для векторизованного условного присвоения. Предполагается, что df[1] уже отсортировано.

df[2] = np.where(df[1].duplicated(), df[2], np.nan)

Если сортировка невозможна:

df[2] = np.where(df[1] != df[1].shift(), np.nan, df[2])

Результат:

   0  1    2
0  A  Z  NaN
1  B  Z  2.1
2  C  Z  3.1
3  D  X  NaN
4  E  X  4.3
5  E  X  2.1
6  F  X  4.3

Эквивалентная логика может быть применена с использованием pd.DataFrame.mask.

0 голосов
/ 09 сентября 2018

Вы можете получить индекс из вашей группы и использовать его в качестве маски с .loc.

import pandas as pd
import numpy as np

df = pd.DataFrame([
    ['A','Z',1.11],
    ['B','Z',2.1],
    ['C','Z',3.1],
    ['D', 'X', 2.1], 
    ['E','X',4.3],
    ['E', 'X', 2.1], 
    ['F','X',4.3]
])

m = df.groupby(by=1).head(1).index
df.loc[m,2] = np.nan

print(df)

ИЛИ вместо этого вы можете использовать duplicated (). Это должно быть быстрее.

m = ~df[1].duplicated()
df.loc[m, 2] = np.nan

возвращается:

   0  1    2
0  A  Z  NaN
1  B  Z  2.1
2  C  Z  3.1
3  D  X  NaN
4  E  X  4.3
5  E  X  2.1
6  F  X  4.3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...