#python #pandas #dask
#питон #pandas #dask
Вопрос:
Допустим, у меня есть следующий фрейм данных:
df1 = pd.DataFrame(data = [1,np.nan,np.nan,1,1,np.nan,1,1,1],
columns = ['X'],
index = ['a', 'a', 'a',
'b', 'b', 'b',
'c', 'c', 'c'])
print(df1)
X
a 1.0
a NaN
a NaN
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Я хочу сохранить только те индексы, которые имеют 2 или более записей, отличных от NaN. В этом случае записи ‘a’ имеют только одно значение, отличное от NaN, поэтому я хочу отбросить его, и мой результат будет:
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Каков наилучший способ сделать это? В идеале я хочу что-то, что работает и с Dask, хотя обычно, если это работает с Pandas, это работает и в Dask.
Ответ №1:
Давайте попробуем filter
out = df.groupby(level=0).filter(lambda x : x.isna().sum()<=1)
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Или мы делаем isin
df[df.index.isin(df.isna().sum(level=0).loc[lambda x : x['X']<=1].index)]
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Комментарии:
1. Оба они работают в Pandas, однако, похоже, это редкий случай (по крайней мере, по моему опыту), когда он не работает в Dask. Ни функция «фильтр», ни суммирование на основе уровней, по-видимому, не реализованы в Dask. Однако я отмечу ответ как решение, поскольку он в основном отвечал на поставленный вопрос. Изначально я решил спросить о Pandas вместо Dask, поскольку у людей обычно больше опыта работы с Pandas, и опять же решения обычно взаимозаменяемы…
Ответ №2:
В качестве другого варианта давайте попробуем фильтровать через GroupBy.transform
и логическое индексирование:
df1[df1['X'].isna().groupby(df1.index).transform('sum') <= 1]
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Или почти таким же образом,
df1[df1.assign(X=df1['X'].isna()).groupby(level=0)['X'].transform('sum') <= 1]
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Возможно, у вас есть хороший шанс заставить это работать и с Dask.
Комментарии:
1. Оба они работают в Pandas, но приводят к следующей ошибке для Dask:
ValueError: Not all divisions are known, can't align partitions. Please use
set_index` для установки индекса.’
Ответ №3:
Я новичок в dask, просмотрел некоторые примеры и документы, однако, похоже, работает следующее;
from dask import dataframe as dd
sd = dd.from_pandas(df1, npartitions=3)
#converts X to boolean checking for isna() and the groupby on index and sum
s = sd.X.isna().groupby(sd.index).sum().compute()
#using the above we can boolean index to check if sum is less than 2 , then use loc
out_dd = sd.loc[list(s[s<2].index)]
out_dd.head(6,npartitions=-1)
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Комментарии:
1. Спасибо за публикацию этого. Я смог использовать часть вашего кода для тестирования своего кода на Dask. И ваш код работает отлично
2. Поскольку OP так и не ответил, я назначу награду за этот ответ, поскольку он был первым, опубликованным после того, как была установлена награда.
3. @cs95 Спасибо 🙂 благодаря щедрости у меня появилась возможность впервые взглянуть на Dask, так что спасибо.
Ответ №4:
Вот другой способ:
dft.loc[dft.groupby(dft.index)['X'].apply(lambda x : x.notnull().sum() > 1)]
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Ответ №5:
Я новичок в Dask. У меня даже не установлен Dask на моем ноутбуке. Я прочитал документацию Dask и обнаружил, что Dask может выполнять reset_index() .
Если это разрешено, вот как подойти к проблеме.
Шаг 1:
df1 = df.reset_index()
df1 даст вам:
>>> df1
index X
0 a 1.0
1 a NaN
2 a NaN
3 b 1.0
4 b 1.0
5 b NaN
6 c 1.0
7 c 1.0
8 c 1.0
Теперь у вас есть индекс и значение X.
Шаг 2:
Чтобы узнать, какое index
значение имеет 2 или более нулей, вы можете сделать:
df1.X.isnull().groupby([df1['index']]).sum().astype(int) < 2
Результатом этого будет:
index
a False
b True
c True
Name: X, dtype: bool
Шаг 3:
Теперь вы применяете это обратно к исходному df
фрейму данных, и отфильтрованными записями будут записи с NaN меньше 2.
df.loc[(df2.X.isnull().groupby([df2['index']]).sum().astype(int) < 2)]
Результатом этого будет:
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0
Я надеюсь, что Даск позволит вам сделать это. Если это произойдет, это будет способ получить результат.
Комментарии:
1. Очень смело с вашей стороны пытаться найти ответ для библиотеки, которую вы даже не установили
2. Установил Dask, опробовал его, и он работает. Это мило. Глядя на решение @anky, мое решение выглядит аналогично. Anky использует список индекса, чтобы получить аналогичный результат
3. В итоге я почти сделал свой код Dask похожим на Anky. Так что я бы выбрал код Анки
Ответ №6:
Вы можете использовать loc
с серией логических значений:
df.loc[df['X'].notna().groupby(level=0).sum().ge(2)]
На первом шаге мы получаем ряд для фильтрации:
mask = df['X'].notna().groupby(level=0).sum().ge(2)
Результат:
a False
b True
c True
Name: X, dtype: bool
На втором шаге мы фильтруем с помощью loc
:
df.loc[mask]
Результат:
X
b 1.0
b 1.0
b NaN
c 1.0
c 1.0
c 1.0