Выберите строку из DataFrame в зависимости от типа объекта (например, str)

Итак, DataFrame говорит:

>>> df = pd.DataFrame({
...                 'A':[1,2,'Three',4],
...                 'B':[1,'Two',3,4]})
>>> df
       A    B
0      1    1
1      2  Two
2  Three    3
3      4    4

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

Например, я хочу выбрать строку, в которой type данных в столбце A есть str.  поэтому он должен печатать что-то вроде:

   A      B
2  Three  3

Чей интуитивно понятный код будет выглядеть следующим образом:

df[type(df.A) == str]

Что явно не работает!

Спасибо, пожалуйста, помогите!

Ответ 1

Это работает:

df[df['A'].apply(lambda x: type(x)==str)]

Ответ 2

Вы можете сделать что-то похожее на то, что вы задаете с помощью

In [14]: df[pd.to_numeric(df.A, errors='coerce').isnull()]
Out[14]: 
       A  B
2  Three  3

Почему только подобное? Поскольку Pandas хранит объекты в однородных столбцах (все записи в столбце одного типа). Несмотря на то, что вы построили DataFrame из гетерогенных типов, все они превращаются в столбцы каждый из самых низких общих знаменателей:

In [16]: df.A.dtype
Out[16]: dtype('O')

Следовательно, вы не можете спросить, какие строки относятся к типу - все они будут одного типа. Что вы можете сделать, это попытаться преобразовать записи в числа и проверить, где не удалось выполнить преобразование (это то, что делает код выше).

Ответ 3

Как правило, плохая идея использовать серию для хранения смешанных числовых и нечисловых типов. Это приведет к тому, что ваша серия будет иметь object dtype, который представляет собой не что иное, как последовательность указателей. Как и list и, действительно, многие операции над такими сериями могут быть более эффективно обработаны list.

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

res = df[[isinstance(value, str) for value in df['A']]]

print(res)

       A  B
2  Three  3

Эквивалент возможен с pd.Series.apply, но это не более чем тонко завуалированный цикл и может быть медленнее, чем понимание списка:

res = df[df['A'].apply(lambda x: isinstance(x, str))]

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

res = df[pd.to_numeric(df['A'], errors='coerce').isnull()]