使用Python对列中的多个值进行复杂的提取和转换

使用Python对列中的多个值进行复杂的提取和转换,python,pandas,numpy,data-analysis,Python,Pandas,Numpy,Data Analysis,我如何获得“df”数据帧的背景: 此数据将从SQL Server拉入Python,然后使用以下命令转换为数据帧: Backup = pyodbc.connect( 'Driver={SQL Server};' 'Server=test\SQLEXPRESS;' 'Database=Backup;' 'Trusted_Connection=yes;' ) crsr = Backup.cursor() fo

我如何获得“df”数据帧的背景:

此数据将从SQL Server拉入Python,然后使用以下命令转换为数据帧:

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 dataframe中有一列,由如下值组成:

 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、香港等?< /P> 期望输出:

 Amsterdam
 Amsterdam
 Amsterdam
 São Paulo
 São Paulo
 São Paulo
 Santa Clara
 Culpepper
 Hong Kong
问题是我不能只在最后一个空白处分开,因为有两个单词的国家被一个空白分开。(圣保罗香港)

我一直致力于:

df["New_Column"]= df["Location"].str.split(" ", n = 1, expand = True) 
我还使用str函数(来自stackoverflow成员的建议)


我让这个正则表达式工作,它有点复杂,所以我将为您分解它

创建数据:

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
df[“city”]=df[“location”].str.extract(r“-.*\s+[A-Z0-9]+\s+(?P.*))
打印(df)
位置城市
上午0点-阿姆斯特丹Equi A2酒店
凌晨1点-阿姆斯特丹Equi A2酒店
凌晨2点-阿姆斯特丹Equi A2酒店
3 GRU-圣保罗的日志资源
4 GRU-圣保罗的日志资源
5 GRU-圣保罗的日志资源
6 SJC1-圣克拉拉博士圣克拉拉
7 IAD-陆地标记导航卡佩珀卡佩珀
8港币1 -香港香港香港
正则表达式解释
r“-.*\s+[A-Z0-9]+\s+(?p.*)$”

  • -
    找到催眠。我们可以忽略在连字符之前发生的一切
  • \s+[A-Z0-9]\s+
    找到连字符后,找到仅包含大写字母和/或数字的子字符串,此外,该子字符串必须由1个或多个空格包围
  • (?P.*)$
    找到上一步后,使用字符串的其余部分作为城市名称,并将其存储在捕获组中

虽然正则表达式是非常有用的工具,但它们往往会留下相当数量的边缘情况。我这里的表达式适用于您的数据,但请确保您对完整数据集进行了一些测试和调整,因为在某些情况下,如果字符串与此处标识的模式不匹配,它仍可能返回NaN。

更新:用户已声明数据来自SQL Server。因此,示例代码已经更新,以显示从SQL提取数据和后续城市提取的示例。(以前,位置数据是从
列表中合成的

原始评论:
正如我在评论中建议的,下面是一个如何使用regex从位置字符串解析城市的示例

此外,此示例(可选)使用
unidecode
库,该库将非ASCII(扩展unicode)字符转换为ASCII,因为它们可能会使r 埃格斯。在文本处理过程中,将非ASCII字符转换为ASCII是一种常见做法

正则表达式模式-尽管看起来很像gobbledy-gook,但它有以下功能:

  • 开始是用于隔离“XX-”模式的字符串的开始
  • 隔离以下“Xxxx”字符
  • 隔离“XXN”以确定从何处开始命名捕获
  • 命名捕获(由
    ?P[\w\s]+
    模式指示)用于将城市名称提取到
    城市
    列中
请注意在字符串的开头和结尾使用了
^
$
。这些命令告诉模式从字符串的开头(
^
)开始,并将模式一直匹配到结尾(
$
)。通常,显式匹配整个字符串非常有用。否则,如果只匹配部分字符串,则可能会得到意外的结果

对于regex构建/测试站点,我发现在编写新模式时非常有用

示例代码: 解析输出:
看看regex,它是一个优秀的文本模式匹配工具;为此,您可以使用
Series.str.extract
函数,将匹配的值(城市名称)提取到一个新列中。谢谢。不用担心,我很乐意。只是弹出一个答案来帮助进一步解释。若列表很小并且不经常更改,我会选择普通字典映射。这个映射可以保存在json文件中。好的,这个列大约有100万行,我得到了这个错误AttributeError:“DataFrame”对象在我运行这个脚本时没有属性“encode”:df['locations]=df['locations']。apply(unidecode)有趣。是否安装了
unidecode
库,并作为
从unidecode导入unidecode
导入?作为库测试,您可以将“圣保罗”保存为字符串并运行
unidecode(“圣保罗”
)来帮助隔离问题。您好,我使用了pip install unidecode并正确安装了它,然后使用了from unidecode import unidecode……。我所做的唯一更改是:df=pd.DataFrame({'locations':[data]})(添加了[]括号是因为我得到了一个标量错误)听起来您的数据帧的构造与我的示例中的数据帧不同,因为1)
数据
对象已经是一个列表,因此不需要额外的
[]
,索引应该自动填充;根据我的例子。所以,让我们重新开始。。。这些位置的数据源是什么?CSV、JSON、web、另一个数据帧?请用原始数据更新原始问题,如果可以的话,我明天早上会看一看。干杯,我会更新的。数据是从我的SQL Server数据库导入的,然后在Python中我将其转换为数据帧。我现在就更新谢谢你Cameron这帮了大忙。我还想知道,如果这个城市有名字,我该如何区分,
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
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)
                       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