[英]Convert columns to string in Pandas
我有来自 SQL 查询的以下 DataFrame:
(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}
转换为字符串的一种方法是使用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"}'
注意:您可以传入一个缓冲区/文件来保存它,以及其他一些选项......
如果您需要将所有列转换为字符串,您可以简单地使用:
df = df.astype(str)
如果您需要除几列之外的所有内容都是字符串/对象,然后返回并将其他列转换为您需要的任何内容(在这种情况下为整数),这将非常有用:
df[["D", "E"]] = df[["D", "E"]].astype(int)
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')
从 pandas 1.0 开始,请考虑改用"string"
类型。
# pandas >= 1.0
s = pd.Series(['a', 'b', 'c'], dtype="string")
s.dtype
# StringDtype
这就是为什么,正如文档所引用的:
您可能会意外地将字符串和非字符串的混合存储在对象 dtype 数组中。 最好有一个专用的 dtype。
object
dtype 破坏了特定于DataFrame.select_dtypes()
操作,例如DataFrame.select_dtypes()
。 没有一种明确的方法可以在排除非文本但仍然是 object-dtype 列的情况下只选择文本。阅读代码时,
object
dtype 数组的内容不如'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.
# 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
在 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
从 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"
列而不是对象的内存使用量。 然而,话虽如此,养成好习惯永远不会太早!
这是另一个,对于将多列转换为字符串而不是单列特别有用:
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
我通常使用这个:
pd['Column'].map(str)
有四种方法可以将列转换为字符串
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)
让我们看看每种类型的性能
#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')
输出
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
与其余两种技术相比, map(str)
和apply(str)
花费的时间更少
在这种情况下,将.apply()
与lambda
转换函数一起使用也适用:
total_rows['ColumnID'] = total_rows['ColumnID'].apply(lambda x: str(x))
对于整个数据帧,您可以使用.applymap()
。 (但无论如何可能.astype()
更快)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.