Конвертировать столбцы в строку в Pandas


179

У меня есть следующий DataFrame из запроса SQL:

(Pdb) pp total_rows
     ColumnID  RespondentCount
0          -1                2
1  3030096843                1
2  3030096845                1

и я хочу повернуть это так:

total_data = total_rows.pivot_table(cols=['ColumnID'])

(Pdb) pp total_data
ColumnID         -1            3030096843   3030096845
RespondentCount            2            1            1

[1 rows x 3 columns]


total_rows.pivot_table(cols=['ColumnID']).to_dict('records')[0]

{3030096843: 1, 3030096845: 1, -1: 2}

но я хочу убедиться, что 303 столбцы приводятся в виде строк вместо целых чисел, чтобы я получил это:

{'3030096843': 1, '3030096845': 1, -1: 2}

Начиная с pandas 1.0, документация рекомендует использовать, astype("string")а неastype(str) по каким-то довольно веским причинам, взгляните.
cs95

Ответы:


333

Один из способов преобразования в строку - использовать astype :

total_rows['ColumnID'] = total_rows['ColumnID'].astype(str)

Однако, возможно, вы ищете to_jsonфункцию, которая преобразует ключи в действительный json (и, следовательно, ваши ключи в строки):

In [11]: df = pd.DataFrame([['A', 2], ['A', 4], ['B', 6]])

In [12]: df.to_json()
Out[12]: '{"0":{"0":"A","1":"A","2":"B"},"1":{"0":2,"1":4,"2":6}}'

In [13]: df[0].to_json()
Out[13]: '{"0":"A","1":"A","2":"B"}'

Примечание: вы можете передать в буфер / файл, чтобы сохранить его, наряду с некоторыми другими параметрами ...


3
Я думаю, что to_string () предпочтительнее из-за сохранения значений NULL stackoverflow.com/a/44008334/3647167
Кит

1
@Keith нулевое сохранение является привлекательным. но документ говорит, что его целью является «рендеринг DataFrame в консольный табличный вывод». я хотел бы, чтобы кто-то авторитетный взвесил
3pitt

to_json()вероятно, не вызывает, astype(str)поскольку он оставляет datetime64 и его подклассы в миллисекундах с эпохи.
Сюсс

1
@ Сасс, я подозреваю, это потому, что у json нет явного формата даты и времени, поэтому вы вынуждены использовать эпоху. То есть, я думаю, что это стандарт.
Энди Хейден

50

Если вам нужно преобразовать ВСЕ столбцы в строки, вы можете просто использовать:

df = df.astype(str)

Это полезно, если вам нужно, чтобы все, кроме нескольких столбцов, были строками / объектами, а затем вернитесь и преобразуйте остальные во все, что вам нужно (в данном случае целое число):

 df[["D", "E"]] = df[["D", "E"]].astype(int) 

28

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

In [76]: import numpy as np
In [77]: import pandas as pd
In [78]: df = pd.DataFrame({
    ...:     'A': [20, 30.0, np.nan],
    ...:     'B': ["a45a", "a3", "b1"],
    ...:     'C': [10, 5, np.nan]})
    ...: 

In [79]: df.dtypes ## Current datatype
Out[79]: 
A    float64
B     object
C    float64
dtype: object

## Multiple columns string conversion
In [80]: df[["A", "C"]] = df[["A", "C"]].astype(str) 

In [81]: df.dtypes ## Updated datatype after string conversion
Out[81]: 
A    object
B    object
C    object
dtype: object


0

панды> = 1.0: пора прекратить использовать astype(str)!

До pandas 1.0 (ну, на самом деле, 0.25) это был дефактный способ объявления серии / столбца в виде строки:

# pandas <= 0.25
# Note to pedants: specifying the type is unnecessary since pandas will 
# automagically infer the type as object
s = pd.Series(['a', 'b', 'c'], dtype=str)
s.dtype
# dtype('O')

Начиная с версии 1.0, рассмотрите возможность использования "string"типа .

# pandas >= 1.0
s = pd.Series(['a', 'b', 'c'], dtype="string")
s.dtype
# StringDtype

Вот почему, как цитируют документы:

  1. Вы можете случайно сохранить смесь строк и не-строк в массиве dtype объекта. Лучше иметь выделенный dtype.

  2. objectdtype прерывает специфичные для dtype операции, такие как DataFrame.select_dtypes(). Не существует четкого способа выделить только текст, исключая нетекстовые, но все еще столбцы типа объекта.

  3. При чтении кода содержимое objectмассива dtype менее понятно, чем 'string'.

Смотрите также раздел о поведенческих различиях между "string"иobject .

Типы расширений (введенные в 0.24 и формализованные в 1.0) ближе к пандам, чем numpy, что хорошо, потому что numpy типы недостаточно мощны. Например, NumPy не имеет никакого способа представления отсутствующих данных в целочисленных данных (поскольку type(NaN) == float). Но панды могут использовать Nullable Integer столбцы .


Почему я должен прекратить его использовать?

Случайное смешивание dtypes
. Первая причина, как указано в документации, заключается в том, что вы можете случайно сохранить нетекстовые данные в столбцах объекта.

# pandas <= 0.25
pd.Series(['a', 'b', 1.23])   # whoops, this should have been "1.23"

0       a
1       b
2    1.23
dtype: object

pd.Series(['a', 'b', 1.23]).tolist()
# ['a', 'b', 1.23]   # oops, pandas was storing this as float all the time.
# pandas >= 1.0
pd.Series(['a', 'b', 1.23], dtype="string")

0       a
1       b
2    1.23
dtype: string

pd.Series(['a', 'b', 1.23], dtype="string").tolist()
# ['a', 'b', '1.23']   # it's a string and we just averted some potentially nasty bugs.

Сложность в различении строк и других объектов Python
Другой очевидный пример - сложнее различить «строки» и «объекты». Объекты по сути являются типом бланкет для любого типа, который не поддерживает векторизованные операции.

Рассматривать,

# Setup
df = pd.DataFrame({'A': ['a', 'b', 'c'], 'B': [{}, [1, 2, 3], 123]})
df
 
   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

До панд 0,25 практически не было возможности различить, что «А» и «В» не имеют данных одного типа.

# pandas <= 0.25  
df.dtypes

A    object
B    object
dtype: object

df.select_dtypes(object)

   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

Начиная с pandas 1.0, это становится намного проще:

# pandas >= 1.0
# Convenience function I call to help illustrate my point.
df = df.convert_dtypes()
df.dtypes

A    string
B    object
dtype: object

df.select_dtypes("string")

   A
0  a
1  b
2  c

Читаемость
Это говорит само за себя ;-)


Хорошо, я должен прекратить использовать это прямо сейчас?

... Нет. На момент написания этого ответа (версия 1.1) преимуществ производительности не было, но в документах ожидается, что будущие усовершенствования значительно повысят производительность и уменьшат использование памяти для "string"столбцов, а не для объектов. С учетом сказанного, однако, никогда не рано формировать хорошие привычки!


-1

Использование .apply()с lambdaфункцией преобразования также работает в этом случае:

total_rows['ColumnID'] = total_rows['ColumnID'].apply(lambda x: str(x))

Для целых фреймов данных вы можете использовать .applymap(). (но в любом случае, вероятно .astype(), быстрее)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.