重铸 Pandas 数据框中的值以满足特定要求

问题描述 投票:0回答:1

我有一个通过从 Excel 电子表格导入创建的 Pandas 数据框。使用

.dtypes
方法时,该列的数据类型为
object
。然而,在单列内,存在
str
int
float
等多种类型的数据。也可能存在缺失值 (
NaN
)。一些字符串值实际上是整数值的字符串表示形式,具体来说,在本例中是 4 位年份。我希望能够将由 4 位数字组成的字符串值重新转换为整数,但保持所有其他值(和数据类型)不变。

举个例子,最小的数据框可能看起来像:

import numpy as np
import pandas as pd
import re

testdf = pd.DataFrame({'col1':['abc','2023',456,789,'2021',4.5,'123',np.nan]})
   col1
0   abc
1  2023
2   456
3   789
4  2021
5   4.5
6   123
7   NaN

与数据类型:

col1    object
dtype: object

但是,各个单元格中的数据类型有所不同:

testdf['col1_types'] = testdf['col1'].apply(type)

   col1       col1_types
0   abc    <class 'str'>
1  2023    <class 'str'>
2   456    <class 'int'>
3   789    <class 'int'>
4  2021    <class 'str'>
5   4.5  <class 'float'>
6   123    <class 'str'>
7   NaN  <class 'float'>

我提出的解决方案涉及如下所示的几个步骤(为了清楚起见,将各个步骤的结果添加为数据框中的新列),但该过程似乎非常笨重。直觉上,我认为应该有一种更简单的方法来做到这一点 - 甚至可能作为单行 - 但我还没有能够解决语法问题。我使用的步骤如下:

第 1 步 - 创建一个掩码,指示哪些单元格包含字符串

strmask = testdf['col1'].apply(type) == str
testdf['strmask'] = strmask

   col1       col1_types  strmask
0   abc    <class 'str'>     True
1  2023    <class 'str'>     True
2   456    <class 'int'>    False
3   789    <class 'int'>    False
4  2021    <class 'str'>     True
5   4.5  <class 'float'>    False
6   123    <class 'str'>     True
7   NaN  <class 'float'>    False

第 2 步 - 测试包含字符串的单元格是否与正则表达式匹配

'20\d{2}'
;如果是这样,则重新转换为
int
,否则保持单元格不变

testdf['col2'] = testdf.loc[phjStrMask,'col1'].apply(lambda c: int(c) if re.match('20\d{2}',c) else c)

   col1       col1_types  strmask  col2
0   abc    <class 'str'>     True   abc
1  2023    <class 'str'>     True  2023
2   456    <class 'int'>    False   NaN
3   789    <class 'int'>    False   NaN
4  2021    <class 'str'>     True  2021
5   4.5  <class 'float'>    False   NaN
6   123    <class 'str'>     True   123
7   NaN  <class 'float'>    False   NaN

第 3 步 - 最初包含字符串以外内容的单元格当前在

NaN
中表示为
col2
。创建一个掩码,指示
col2
中的哪些单元格包含
NaN
,然后替换为原始内容(在
col1
中)

nanmask = testdf['col2'].isnull()
testdf.loc[nanmask,'col2'] = testdf['col1']

   col1       col1_types  strmask  col2
0   abc    <class 'str'>     True   abc
1  2023    <class 'str'>     True  2023
2   456    <class 'int'>    False   456
3   789    <class 'int'>    False   789
4  2021    <class 'str'>     True  2021
5   4.5  <class 'float'>    False   4.5
6   123    <class 'str'>     True   123
7   NaN  <class 'float'>    False   NaN

第 4 步 - 确认新列中的数据类型符合预期

testdf['col2_types'] = testdf['col2'].apply(type)

   col1       col1_types  strmask  col2       col2_types
0   abc    <class 'str'>     True   abc    <class 'str'>
1  2023    <class 'str'>     True  2023    <class 'int'>
2   456    <class 'int'>    False   456    <class 'int'>
3   789    <class 'int'>    False   789    <class 'int'>
4  2021    <class 'str'>     True  2021    <class 'int'>
5   4.5  <class 'float'>    False   4.5  <class 'float'>
6   123    <class 'str'>     True   123    <class 'str'>
7   NaN  <class 'float'>    False   NaN  <class 'float'>

上面的过程看似可行,但却冗长且笨拙。有没有办法直接将

int
中与正则表达式匹配的字符串值重新转换为
col1
,而无需经过一系列中间步骤?

python-3.x pandas dataframe integer
1个回答
0
投票

使用

str.fullmatch
构建布尔掩码并更改 dtype:

m = testdf['col1'].str.fullmatch(r'\d{4}').eq(True)

testdf.loc[m, 'col1'] = testdf.loc[m, 'col1'].astype(int)
© www.soinside.com 2019 - 2024. All rights reserved.