NaN в pandas Series.tolist () ведет себя иначе, чем NaN в списке - PullRequest
2 голосов
/ 08 апреля 2020

Почему

>> import pandas as pd
>> import numpy as np

>> list(pd.Series([np.nan, np.nan, 2, np.nan, 2])) == [np.nan, np.nan, 2, np.nan, 2]

возвращает False? Я получаю тот же результат с pd.Series([np.nan, np.nan, 2, np.nan, 2]).tolist(). Я пытался посчитать самый распространенный элемент в объекте pandas groupby (то есть, в основном, pandas Series) с помощью следующей функции

def get_most_common(srs):
    """
    Returns the most common value in a list. For ties, it returns whatever
    value collections.Counter.most_common(1) gives.
    """
    from collections import Counter

    x = list(srs)
    my_counter = Counter(x)
    most_common_value = my_counter.most_common(1)[0][0]

    return most_common_value

и только что понял, что получаю неправильные значения для нескольких NaN даже если у меня есть шаг x = list(srs).

РЕДАКТИРОВАТЬ: просто чтобы уточнить, почему это проблема для меня:

>>> from collections import Counter
>>> Counter(pd.Series([np.nan, np.nan, np.nan, 2, 2, 1, 5]).tolist())
Counter({nan: 1, nan: 1, nan: 1, 2.0: 2, 1.0: 1, 5.0: 1}) # each nan is counted differently
>>> Counter([np.nan, np.nan, np.nan, 2, 2, 1, 5])
Counter({nan: 3, 2: 2, 1: 1, 5: 1}) # nan count of 3 is correct

Ответы [ 2 ]

3 голосов
/ 08 апреля 2020

Проблема root, как уже говорилось @emilaz, заключается в том, что nan != nan во всех случаях. Однако в вашем наблюдении важна ссылка на объект.

Обратите внимание на следующие ссылки на объекты между list и pd.Series:

>>> s = pd.Series([np.nan, np.nan, np.nan, 2, 2, 1, 5])
>>> s.apply(id)
0    149706480
1    202463472
2    202462336
3    149706912
4    149706288
5    149708784
6    149707200
dtype: int64

>>> l = [np.nan, np.nan, np.nan, 2, 2, 1, 5]
>>> list(map(id, l))
[68634768, 68634768, 68634768, 1389126848, 1389126848, 1389126832, 1389126896]

Объект np.nan имеет ту же ссылку как импортированный объект np.nan в list, тогда как для каждого Series создается новая ссылка (что имеет смысл для использования pandas).

Поэтому ответ не в том, чтобы сравнивать nan таким образом. pandas имеет свои собственные способы справиться с nan, поэтому, в зависимости от вашей реальной деятельности, может быть гораздо более простой ответ (например, df.groupby('some col').count()), чем вы предполагали.

2 голосов
/ 08 апреля 2020

В python, приравнивая к nan, всегда возвращает False. Таким образом, ожидается следующее поведение:

import numpy as np
np.nan == np.nan
>>>> False

Вот почему ваши сравнения списков возвращают False.

Возможный обходной путь будет следующим:

import pandas as pd
import numpy as np

foo= list(pd.Series([np.nan, np.nan, 2, np.nan, 2]))
bar= [np.nan, np.nan, 2, np.nan, 2]

np.allclose(foo,bar, equal_nan=True)
>>>> True

Это может заинтересовать you: сравнение numpy массивов, содержащих NaN .

Для поиска наиболее распространенного элемента я бы предложил использовать pandas и метод value_counts():

pd.Series([np.nan, np.nan, 2, np.nan, 2]).value_counts()
>>>> 2.0  2

Если вы заботитесь о количестве наночастиц, вы можете просто передать dropna=False методу:

pd.Series([np.nan, np.nan, 2, np.nan, 2]).value_counts()
>>>> NaN  3
     2.0  2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...