Перетворення стовпців у рядок у 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}

Відповіді:


332

Один із способів перетворення в рядок - це використання 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 привабливе. але doc каже, що його мета - "Надати DataFrame на консольний друкований табличний вихід". Я хотів би, щоб хтось авторитетний зважив
3pitt

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

1
@Sussch Я підозрюю, що це тому, що json не має чіткого формату дати, тому ви начебто змушені використовувати епоху. Що сказати, я думаю, що це стандарт.
Енді Хайден

49

Якщо вам потрібно перетворити ВСІ стовпці на рядки, ви можете просто скористатися:

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

pandas> = 1.0: пора припинити використання astype(str)!

До панд 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')

Починаючи з pandas 1.0, використовуючи натомість "string"тип .

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

Ось чому, як цитують документи:

  1. Ви можете випадково зберегти суміш рядків і не рядків в масиві типових об'єктів. Краще мати виділений тип.

  2. objectdtype розбиває конкретні операції типу DataFrame.select_dtypes(). Не існує чіткого способу вибору просто тексту, виключаючи нетекстові, але все-таки стовпці з типом об'єкта.

  3. Під час читання коду вміст objectмасиву dtype менш зрозуміло, ніж 'string'.

Дивіться також розділ про поведінкові відмінності між "string"таobject .

Типи розширень (введені в 0,24 та формалізовані в 1,0) ближче до панд, ніж numpy, що добре, тому що типи numpy недостатньо потужні. Наприклад, NumPy не має жодного способу подання відсутніх даних у цілих даних (з тих пір type(NaN) == float). Але панди можуть використовувати стовпці Nullable Integer .


Чому я повинен припинити його використання?

Випадкове змішування типів
Перша причина, зазначена в документах, полягає в тому, що ви можете випадково зберігати нетекстові дані в стовпцях об'єктів.

# 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 практично не було можливості відрізнити те, що "A" та "B" не мають одного типу даних.

# 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

З панд 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.