使用 Python 对列中的多个值进行复杂的提取和转换
Complex extraction and transformation of multiple values within a column using Python
我如何获得 'df' Dataframe 的背景:
此数据正在从 SQL 服务器拉入 Python,然后使用 Pandas:
转换为数据帧
Backup = pyodbc.connect(
'Driver={SQL Server};'
'Server=test\SQLEXPRESS;'
'Database=Backup;'
'Trusted_Connection=yes;'
)
crsr = Backup.cursor()
for table_name in crsr.tables(tableType='TABLE'):
print(table_name)
cursor = Backup.cursor()
sql = "select TOP 20* from dbo.table$"
cursor.execute(sql)
for data in cursor.fetchall():
print (data)
df = pandas.read_sql(sql,Backup)
df
我的 df 数据框中有一列包含如下所示的值:
Location
AM - Equi A2 Amsterdam
AM - Equi A2 Amsterdam
AM - Equi A2 Amsterdam
GRU - log Equ SP São Paulo
GRU - log Equ SP São Paulo
GRU - log Equ SP São Paulo
SJC1 - DR Santa Clara
IAD - Terremark NAV Culpepper
HKG1 - Equin HK Hong Kong
困境:
如何只提取实际地点,例如:圣保罗、阿姆斯特丹、Culpepper、香港等?
期望的输出:
Amsterdam
Amsterdam
Amsterdam
São Paulo
São Paulo
São Paulo
Santa Clara
Culpepper
Hong Kong
问题是我不能只在最后一个空格 space 上拆分,因为国家/地区有两个单词,被一个空格拆分 space。 (香港,圣保罗)
我一直在做的事情:
df["New_Column"]= df["Location"].str.split(" ", n = 1, expand = True)
我也在使用 str 函数(来自 Whosebug 成员的建议)
df.str.extract()
我让这个正则表达式起作用了,它有点复杂,所以我会为你分解它。
创建数据:
data = """
AM - Equi A2 Amsterdam
AM - Equi A2 Amsterdam
AM - Equi A2 Amsterdam
GRU - log Equ SP São Paulo
GRU - log Equ SP São Paulo
GRU - log Equ SP São Paulo
SJC1 - DR Santa Clara
IAD - Terremark NAV Culpepper
HKG1 - Equin HK Hong Kong
""".strip().split("\n")
df = pd.DataFrame(data, columns=["location"])
df["location"] = df["location"].str.strip()
print(df)
location
0 AM - Equi A2 Amsterdam
1 AM - Equi A2 Amsterdam
2 AM - Equi A2 Amsterdam
3 GRU - log Equ SP São Paulo
4 GRU - log Equ SP São Paulo
5 GRU - log Equ SP São Paulo
6 SJC1 - DR Santa Clara
7 IAD - Terremark NAV Culpepper
8 HKG1 - Equin HK Hong Kong
通过Series.str.extract
应用我们的正则表达式
df["city"] = df["location"].str.extract(r"-.*\s+[A-Z0-9]+\s+(?P<city>.*)")
print(df)
location city
0 AM - Equi A2 Amsterdam Amsterdam
1 AM - Equi A2 Amsterdam Amsterdam
2 AM - Equi A2 Amsterdam Amsterdam
3 GRU - log Equ SP São Paulo São Paulo
4 GRU - log Equ SP São Paulo São Paulo
5 GRU - log Equ SP São Paulo São Paulo
6 SJC1 - DR Santa Clara Santa Clara
7 IAD - Terremark NAV Culpepper Culpepper
8 HKG1 - Equin HK Hong Kong Hong Kong
正则表达式解释r"-.*\s+[A-Z0-9]+\s+(?P<city>.*)$"
:
-
找到 hypen。我们可以忽略连字符之前出现的所有内容。
\s+[A-Z0-9]\s+
找到连字符后,找到一个只包含大写字母 and/or 数字的子串,另外这个子串必须被 1 个或多个空格包围。
(?P<city>.*)$
找到上一步后,将字符串的其余部分用作城市名称并将其存储在捕获组中。
虽然正则表达式是非常有用的工具,但它们往往会留下相当多的边缘情况。我在此处使用的表达式适用于您的数据,但请确保您对完整数据集进行了一些测试和调整,因为如果您的字符串与此处标识的模式不匹配,在某些情况下它仍然可能 return NaN。
更新: 用户声明数据来自 SQL 服务器。因此,示例代码已更新,以显示从 SQL 中提取数据和随后提取城市的示例。 (以前,位置数据是从 list
合成的。)
原评论:
正如我在评论中所推荐的,这里是一个如何使用正则表达式从位置字符串解析城市的示例。
此外,此示例(可选)使用 unidecode
库将 non-ASCII(扩展的 unicode)字符转换为 ASCII,因为它们可能会使 r
正则表达式。在文本处理程序中将 non-ASCII 个字符转换为 ASCII 是一种常见的做法。
正则表达式模式 - 虽然它看起来很像 gobbledy-gook,但执行以下操作:
- Starts 是用于隔离 'XX - ' 模式的字符串的开头
- 隔离以下 'Xxxx' 个字符
- 隔离 'XXN' 以确定命名捕获的开始位置
- 命名捕获(由
?P<city>[\w\s]+
模式表示)用于将城市名称提取到 city
列
注意在字符串的开头和结尾使用 ^
和 $
。这些告诉模式从字符串的开头 (^
) 开始,并匹配模式一直到结尾 ($
)。通常,显式匹配整个字符串非常有用。否则,如果只匹配了部分字符串,您可能会得到意想不到的结果。
Here is a link 到正则表达式 building/testing 站点 我发现在编写新模式时非常有帮助。
示例代码:
import pandas as pd
import re
from unidecode import unidecode # optional
# Database connection code ...
# ...
# ...
# Query data from SQL into a DataFrame.
# We use MySQL, so this line will be different for you;
# use your existing code here.
df = pd.read_sql(sql="select * from locations", con=engine)
# Define regex pattern.
exp = re.compile(r'^[A-Z0-9\s\-]+[\w\s]+[A-Z0-9]+\s(?P<city>[\w\s]+)$')
# Convert non-ASCII characters to ASCII. (optional)
# df['locations'] = df['locations'].apply(unidecode) # Extract the city name.
df['cities'] = df['locations'].str.extract(exp, expand=True)
来自SQL的原始数据:
locations
0 AM - Equi A2 Amsterdam
1 AM - Equi A2 Amsterdam
2 AM - Equi A2 Amsterdam
3 GRU - log Equ SP São Paulo
4 GRU - log Equ SP São Paulo
5 GRU - log Equ SP São Paulo
6 SJC1 - DR Santa Clara
7 IAD - Terremark NAV Culpepper
8 HKG1 - Equin HK Hong Kong
解析后的输出:
locations cities
0 AM - Equi A2 Amsterdam Amsterdam
1 AM - Equi A2 Amsterdam Amsterdam
2 AM - Equi A2 Amsterdam Amsterdam
3 GRU - log Equ SP São Paulo São Paulo
4 GRU - log Equ SP São Paulo São Paulo
5 GRU - log Equ SP São Paulo São Paulo
6 SJC1 - DR Santa Clara Santa Clara
7 IAD - Terremark NAV Culpepper Culpepper
8 HKG1 - Equin HK Hong Kong Hong Kong
我如何获得 'df' Dataframe 的背景:
此数据正在从 SQL 服务器拉入 Python,然后使用 Pandas:
转换为数据帧Backup = pyodbc.connect(
'Driver={SQL Server};'
'Server=test\SQLEXPRESS;'
'Database=Backup;'
'Trusted_Connection=yes;'
)
crsr = Backup.cursor()
for table_name in crsr.tables(tableType='TABLE'):
print(table_name)
cursor = Backup.cursor()
sql = "select TOP 20* from dbo.table$"
cursor.execute(sql)
for data in cursor.fetchall():
print (data)
df = pandas.read_sql(sql,Backup)
df
我的 df 数据框中有一列包含如下所示的值:
Location
AM - Equi A2 Amsterdam
AM - Equi A2 Amsterdam
AM - Equi A2 Amsterdam
GRU - log Equ SP São Paulo
GRU - log Equ SP São Paulo
GRU - log Equ SP São Paulo
SJC1 - DR Santa Clara
IAD - Terremark NAV Culpepper
HKG1 - Equin HK Hong Kong
困境:
如何只提取实际地点,例如:圣保罗、阿姆斯特丹、Culpepper、香港等?
期望的输出:
Amsterdam
Amsterdam
Amsterdam
São Paulo
São Paulo
São Paulo
Santa Clara
Culpepper
Hong Kong
问题是我不能只在最后一个空格 space 上拆分,因为国家/地区有两个单词,被一个空格拆分 space。 (香港,圣保罗)
我一直在做的事情:
df["New_Column"]= df["Location"].str.split(" ", n = 1, expand = True)
我也在使用 str 函数(来自 Whosebug 成员的建议)
df.str.extract()
我让这个正则表达式起作用了,它有点复杂,所以我会为你分解它。
创建数据:
data = """
AM - Equi A2 Amsterdam
AM - Equi A2 Amsterdam
AM - Equi A2 Amsterdam
GRU - log Equ SP São Paulo
GRU - log Equ SP São Paulo
GRU - log Equ SP São Paulo
SJC1 - DR Santa Clara
IAD - Terremark NAV Culpepper
HKG1 - Equin HK Hong Kong
""".strip().split("\n")
df = pd.DataFrame(data, columns=["location"])
df["location"] = df["location"].str.strip()
print(df)
location
0 AM - Equi A2 Amsterdam
1 AM - Equi A2 Amsterdam
2 AM - Equi A2 Amsterdam
3 GRU - log Equ SP São Paulo
4 GRU - log Equ SP São Paulo
5 GRU - log Equ SP São Paulo
6 SJC1 - DR Santa Clara
7 IAD - Terremark NAV Culpepper
8 HKG1 - Equin HK Hong Kong
通过Series.str.extract
df["city"] = df["location"].str.extract(r"-.*\s+[A-Z0-9]+\s+(?P<city>.*)")
print(df)
location city
0 AM - Equi A2 Amsterdam Amsterdam
1 AM - Equi A2 Amsterdam Amsterdam
2 AM - Equi A2 Amsterdam Amsterdam
3 GRU - log Equ SP São Paulo São Paulo
4 GRU - log Equ SP São Paulo São Paulo
5 GRU - log Equ SP São Paulo São Paulo
6 SJC1 - DR Santa Clara Santa Clara
7 IAD - Terremark NAV Culpepper Culpepper
8 HKG1 - Equin HK Hong Kong Hong Kong
正则表达式解释r"-.*\s+[A-Z0-9]+\s+(?P<city>.*)$"
:
-
找到 hypen。我们可以忽略连字符之前出现的所有内容。\s+[A-Z0-9]\s+
找到连字符后,找到一个只包含大写字母 and/or 数字的子串,另外这个子串必须被 1 个或多个空格包围。(?P<city>.*)$
找到上一步后,将字符串的其余部分用作城市名称并将其存储在捕获组中。
虽然正则表达式是非常有用的工具,但它们往往会留下相当多的边缘情况。我在此处使用的表达式适用于您的数据,但请确保您对完整数据集进行了一些测试和调整,因为如果您的字符串与此处标识的模式不匹配,在某些情况下它仍然可能 return NaN。
更新: 用户声明数据来自 SQL 服务器。因此,示例代码已更新,以显示从 SQL 中提取数据和随后提取城市的示例。 (以前,位置数据是从 list
合成的。)
原评论:
正如我在评论中所推荐的,这里是一个如何使用正则表达式从位置字符串解析城市的示例。
此外,此示例(可选)使用 unidecode
库将 non-ASCII(扩展的 unicode)字符转换为 ASCII,因为它们可能会使 r
正则表达式。在文本处理程序中将 non-ASCII 个字符转换为 ASCII 是一种常见的做法。
正则表达式模式 - 虽然它看起来很像 gobbledy-gook,但执行以下操作:
- Starts 是用于隔离 'XX - ' 模式的字符串的开头
- 隔离以下 'Xxxx' 个字符
- 隔离 'XXN' 以确定命名捕获的开始位置
- 命名捕获(由
?P<city>[\w\s]+
模式表示)用于将城市名称提取到city
列
注意在字符串的开头和结尾使用 ^
和 $
。这些告诉模式从字符串的开头 (^
) 开始,并匹配模式一直到结尾 ($
)。通常,显式匹配整个字符串非常有用。否则,如果只匹配了部分字符串,您可能会得到意想不到的结果。
Here is a link 到正则表达式 building/testing 站点 我发现在编写新模式时非常有帮助。
示例代码:
import pandas as pd
import re
from unidecode import unidecode # optional
# Database connection code ...
# ...
# ...
# Query data from SQL into a DataFrame.
# We use MySQL, so this line will be different for you;
# use your existing code here.
df = pd.read_sql(sql="select * from locations", con=engine)
# Define regex pattern.
exp = re.compile(r'^[A-Z0-9\s\-]+[\w\s]+[A-Z0-9]+\s(?P<city>[\w\s]+)$')
# Convert non-ASCII characters to ASCII. (optional)
# df['locations'] = df['locations'].apply(unidecode) # Extract the city name.
df['cities'] = df['locations'].str.extract(exp, expand=True)
来自SQL的原始数据:
locations
0 AM - Equi A2 Amsterdam
1 AM - Equi A2 Amsterdam
2 AM - Equi A2 Amsterdam
3 GRU - log Equ SP São Paulo
4 GRU - log Equ SP São Paulo
5 GRU - log Equ SP São Paulo
6 SJC1 - DR Santa Clara
7 IAD - Terremark NAV Culpepper
8 HKG1 - Equin HK Hong Kong
解析后的输出:
locations cities
0 AM - Equi A2 Amsterdam Amsterdam
1 AM - Equi A2 Amsterdam Amsterdam
2 AM - Equi A2 Amsterdam Amsterdam
3 GRU - log Equ SP São Paulo São Paulo
4 GRU - log Equ SP São Paulo São Paulo
5 GRU - log Equ SP São Paulo São Paulo
6 SJC1 - DR Santa Clara Santa Clara
7 IAD - Terremark NAV Culpepper Culpepper
8 HKG1 - Equin HK Hong Kong Hong Kong