Как эффективно разместить NaN в Pandas Dataframe? - PullRequest
2 голосов
/ 29 января 2020

У меня есть df, который содержит категориальные и числовые данные

df = {'Name':['Tom', 'nick', 'krish', 'jack'], 
       'Address':['Oxford', 'Cambridge', 'Xianjiang', 'Wuhan'], 
       'Age':[20, 21, 19, 18], 
       'Weight':[50, 61, 69, 78]} 
df = pd.DataFrame(df) 

Мне нужно произвольно заменить 50% в каждом столбце на NaN, поэтому результат может выглядеть следующим образом

enter image description here

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

Ответы [ 3 ]

1 голос
/ 29 января 2020

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

df_final =  df.apply(lambda x: x.sample(frac=0.5)).reindex(df.index)

Out[175]:
    Name    Address   Age  Weight
0    Tom        NaN   NaN    50.0
1    NaN        NaN   NaN    61.0
2  krish  Xianjiang  19.0     NaN
3    NaN      Wuhan  18.0     NaN
1 голос
/ 29 января 2020

В три раза улучшив производительность предыдущих ответов, в основном вдохновленных @jezrael, я предлагаю использовать argpartition вместо argsort, поскольку выполняемая сортировка довольно бесполезна:

df1 = df.mask(np.random.rand(*df.shape).argpartition(0, axis=0) >= df.shape[0] // 2)
print(df1)
   Name    Address   Age  Weight
0   NaN     Oxford   NaN    50.0
1  nick  Cambridge  21.0    61.0
2   NaN        NaN   NaN     NaN
3  jack        NaN  18.0     NaN

Сравнение производительности

# Reusing the same comparison dataset
df = pd.concat([df] * 50000, ignore_index=True)
df = pd.concat([df] * 50, ignore_index=True, axis=1)


# @Andy's answer, using apply and sample
%timeit df.apply(lambda x: x.sample(frac=0.5)).reindex(df.index)
9.72 s ± 532 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# @jezrael's answer, based on mask, np random and argsort
%timeit df.mask(np.random.rand(*df.shape).argsort(axis=0) >= df.shape[0] // 2)
8.23 s ± 732 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# This answer, based on mask, np random and argpartition
%timeit df.mask(np.random.rand(*df.shape).argpartition(0, axis=0) >= df.shape[0] // 2)
2.54 s ± 98.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
0 голосов
/ 29 января 2020

Это можно сделать, взяв случайные числа в диапазоне ваших кортежей и запустив над ними al oop и считая это индексом для замены на NaaN

пример: если у вас есть 10 кортежей из случайного числа диапазон генераторной установки от 0 до 9 и принять результат вышеуказанной операции в качестве индекса для замены на NaN

...