在Pandas中将列转换为字符串

son*_*tek 130 python numpy pandas

我有一个SQL查询的以下DataFrame:

(Pdb) pp total_rows
     ColumnID  RespondentCount
0          -1                2
1  3030096843                1
2  3030096845                1
Run Code Online (Sandbox Code Playgroud)

我想像这样转动它:

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}
Run Code Online (Sandbox Code Playgroud)

但我想确保将303列作为字符串而不是整数进行转换,以便我得到:

{'3030096843': 1, '3030096845': 1, -1: 2}
Run Code Online (Sandbox Code Playgroud)

And*_*den 267

转换为字符串的一种方法是使用astype:

total_rows['ColumnID'] = total_rows['ColumnID'].astype(str)
Run Code Online (Sandbox Code Playgroud)

但是,也许你正在寻找这个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"}'
Run Code Online (Sandbox Code Playgroud)

注意:你可以传入一个缓冲区/文件来保存它,以及其他一些选项......

  • 我认为to_string()更可取,因为它保留了NULL http://stackoverflow.com/a/44008334/3647167 (2认同)
  • @Keith 空值保存很有吸引力。但文档说它的目的是“将数据帧渲染到控制台友好的表格输出”。我希望有权威的人来衡量 (2认同)

cs9*_*s95 45

pandas >= 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')
Run Code Online (Sandbox Code Playgroud)

从 pandas 1.0 开始,考虑使用"string"type代替。

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

这就是为什么,正如文档所引用的:

  1. 您可能会意外地将字符串和非字符串的混合存储在对象 dtype 数组中。最好有一个专用的 dtype。

  2. objectdtype 会破坏 dtype 特定的操作,例如DataFrame.select_dtypes(). 没有一种明确的方法可以在排除非文本但仍然是 object-dtype 列的情况下只选择文本。

  3. 阅读代码时,objectdtype 数组的内容不如'string'.

另请参阅关于之间的行为差​​异部分"string"object

扩展类型(在 0.24 中引入并在 1.0 中正式化)比 numpy 更接近 Pandas,这很好,因为 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.
Run Code Online (Sandbox Code Playgroud)
# 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.
Run Code Online (Sandbox Code Playgroud)

区分字符串和其他 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
Run Code Online (Sandbox Code Playgroud)

在 pandas 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
Run Code Online (Sandbox Code Playgroud)

从 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
Run Code Online (Sandbox Code Playgroud)

可读性
这是不言自明的;-)


好的,我现在应该停止使用它吗?

...不。在撰写此答案(版本 1.1)时,没有性能优势,但文档预计未来的增强功能将显着提高性能并减少"string"列而不是对象的内存使用量。然而,话虽如此,养成好习惯永远不会太早!

  • 没错。但有时,如果你试图解决 Kaggle 泰坦尼克竞赛,其中 Pclass 表示为 1,2 和 3,就会发生这种情况。这里它应该是像字符串格式那样的分类而不是数字。为了解决这个问题,在这种情况下, str 代替了 string 有所帮助。无论如何,谢谢它对角色有用。感谢您分享此文档详细信息。 (3认同)
  • @cs95 非常有见地..感谢分享:) (2认同)

Mik*_*ike 27

如果您需要将所有列转换为字符串,您只需使用:

df = df.astype(str)
Run Code Online (Sandbox Code Playgroud)

如果您需要除了几列之外的所有内容都是字符串/对象,那么这很有用,然后返回并将其他内容转换为您需要的任何内容(在本例中为整数):

 df[["D", "E"]] = df[["D", "E"]].astype(int) 
Run Code Online (Sandbox Code Playgroud)

  • 我更喜欢你的答案 - 因为OP要求“所有”列,而不是单个列。 (3认同)

Sur*_*rya 24

这是另一个,特别适用于 将多个列转换为字符串而不是单个列:

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
Run Code Online (Sandbox Code Playgroud)


Gov*_*nda 24

将列转换为字符串有四种方法

1. astype(str)
df['column_name'] = df['column_name'].astype(str)

2. values.astype(str)
df['column_name'] = df['column_name'].values.astype(str)

3. map(str)
df['column_name'] = df['column_name'].map(str)

4. apply(str)
df['column_name'] = df['column_name'].apply(str)
Run Code Online (Sandbox Code Playgroud)

让我们看看每种类型的性能

#importing libraries
import numpy as np
import pandas as pd
import time

#creating four sample dataframes using dummy data
df1 = pd.DataFrame(np.random.randint(1, 1000, size =(10000000, 1)), columns =['A'])
df2 = pd.DataFrame(np.random.randint(1, 1000, size =(10000000, 1)), columns =['A'])
df3 = pd.DataFrame(np.random.randint(1, 1000, size =(10000000, 1)), columns =['A'])
df4 = pd.DataFrame(np.random.randint(1, 1000, size =(10000000, 1)), columns =['A'])

#applying astype(str)
time1 = time.time()
df1['A'] = df1['A'].astype(str)
print('time taken for astype(str) : ' + str(time.time()-time1) + ' seconds')

#applying values.astype(str)
time2 = time.time()
df2['A'] = df2['A'].values.astype(str)
print('time taken for values.astype(str) : ' + str(time.time()-time2) + ' seconds')

#applying map(str)
time3 = time.time()
df3['A'] = df3['A'].map(str)
print('time taken for map(str) : ' + str(time.time()-time3) + ' seconds')

#applying apply(str)
time4 = time.time()
df4['A'] = df4['A'].apply(str)
print('time taken for apply(str) : ' + str(time.time()-time4) + ' seconds')
Run Code Online (Sandbox Code Playgroud)

输出

time taken for astype(str): 5.472359895706177 seconds
time taken for values.astype(str): 6.5844292640686035 seconds
time taken for map(str): 2.3686647415161133 seconds
time taken for apply(str): 2.39758563041687 seconds
Run Code Online (Sandbox Code Playgroud)

map(str)apply(str)其余两种技术相比,花费的时间更少

  • 你的结果很可疑。`.astype(str)` 绝对应该是最快的。使用“%timeit”可以获得更可靠的结果(为您提供多次试验的平均值)。“%timeit”为“.astype(str)”提供了 654 毫秒,为“.values.astype(str)”提供了 1.4 秒,为“.map(str)”提供了 2.11 秒,为“.apply(str)”提供了 1.74 秒)`。 (7认同)

小智 8

我通常用这个:

pd['Column'].map(str)
Run Code Online (Sandbox Code Playgroud)