Python 如何迭代数据帧的所有行,将查找函数应用于字符串值,并将结果应用于新列?

Python 如何迭代数据帧的所有行,将查找函数应用于字符串值,并将结果应用于新列?,python,pandas,function,Python,Pandas,Function,我有一个数据框,每行(个人)有几列个人数据。我想应用一个函数在区域列表中查找每个人的城市或州,然后将结果应用到同一数据框中的新列“Region” 我已经能够使用一个非常简化的数据框,对颜色和车辆进行分类,从而实现相同的操作(见下文)。但当我尝试使用个人数据时,它不会以同样的方式工作,我不明白为什么 我已经阅读了很多关于lambda函数的thead,但是我认为我要问的太复杂了。大多数解决方案处理数值数据,我使用字符串,但正如我所说的,我能够使用一个数据集。显然我是新来的。我也希望你能给我一些建议,

我有一个数据框,每行(个人)有几列个人数据。我想应用一个函数在区域列表中查找每个人的城市或州,然后将结果应用到同一数据框中的新列“Region”

我已经能够使用一个非常简化的数据框,对颜色和车辆进行分类,从而实现相同的操作(见下文)。但当我尝试使用个人数据时,它不会以同样的方式工作,我不明白为什么

我已经阅读了很多关于lambda函数的thead,但是我认为我要问的太复杂了。大多数解决方案处理数值数据,我使用字符串,但正如我所说的,我能够使用一个数据集。显然我是新来的。我也希望你能给我一些建议,告诉我如何把新专栏作为函数的一部分来构建,而不是把它作为一个单独的步骤来构建,但这并不像主要问题那样让我沮丧

此示例适用于: 测向显示器:

    one two three   type
0   1   A   car     
1   2   B   bus     
2   3   C   red     
3   4   D   blue    
4   5   E   truck   
5   6   F   pencil  
6   7   G   yellow  
7   8   H   green   
    Last Name   First Name  Code    Deparment   City        State   Region
0   SMITH       TOM         12  Research        NEW YORK    NY  
1   JONES       DICK        34  Management      BOSTON      MA  
2   WILSON      HARRY       56  Maintenance     SAN FRANCISCO   CA  
3   DOYLE       MICHAEL     78  Marketing       DALLAS      TX  
4   ANDERSON    KEVIN       90  IT              DETROIT     MI  
现在定义列表和自定义函数:

# Definte lists of colors and vehicles
colors = ['red','blue','green','yellow']
vehicles = ['car','truck','bus','motorcycle']

# Create function 'celltype' to return values based on x
def celltype (x):
    if x in colors: return 'color' 
    elif x in vehicles: return 'vehicle'
    else: return 'other'
# Write loop to iterate through df rows and apply function 'celltype' to column 'three' in each row
for index, row in df.iterrows(): 
    row['type'] = celltype(row['three'])
然后构造一个循环,遍历每一行并应用函数:

# Definte lists of colors and vehicles
colors = ['red','blue','green','yellow']
vehicles = ['car','truck','bus','motorcycle']

# Create function 'celltype' to return values based on x
def celltype (x):
    if x in colors: return 'color' 
    elif x in vehicles: return 'vehicle'
    else: return 'other'
# Write loop to iterate through df rows and apply function 'celltype' to column 'three' in each row
for index, row in df.iterrows(): 
    row['type'] = celltype(row['three'])
在这种情况下,结果正是我想要的:

    one two three   type
0   1   A   car     vehicle
1   2   B   bus     vehicle
2   3   C   red     color
3   4   D   blue    color
4   5   E   truck   vehicle
5   6   F   pencil  other
6   7   G   yellow  color
7   8   H   green   color

这个例子不起作用,我不知道为什么: df1显示:

    one two three   type
0   1   A   car     
1   2   B   bus     
2   3   C   red     
3   4   D   blue    
4   5   E   truck   
5   6   F   pencil  
6   7   G   yellow  
7   8   H   green   
    Last Name   First Name  Code    Deparment   City        State   Region
0   SMITH       TOM         12  Research        NEW YORK    NY  
1   JONES       DICK        34  Management      BOSTON      MA  
2   WILSON      HARRY       56  Maintenance     SAN FRANCISCO   CA  
3   DOYLE       MICHAEL     78  Marketing       DALLAS      TX  
4   ANDERSON    KEVIN       90  IT              DETROIT     MI  
同样,定义列表和函数:

# Define lists for regions
east = ['NEW YORK','BOSTON']
west = ['SAN FRANCISCO','LOS ANGELES']
south = ['TX']

# Create function 'region' to return values based on x
def region (x):
    if x in east: return 'east' 
    elif x in west: return 'west'
    elif x in south: return 'south'
    else: return 'other'

# Write loop to iterate through df1 rows and apply function 'region' to column 'City' in each row
for index, row in df1.iterrows(): 
    row['Region'] = region(row['City'])
    if row['Region'] == 'other': row['Region'] = region(row['State'])

这将导致df1保持不变。“区域”列仍然为空。我们应该看到“东”、“东”、“西”、“南”、“其他”。代码中唯一的区别是附加的“if”语句,用于按州捕获Dallas(这是我的真实数据集所需要的)。但是我认为这行代码是正确的,没有它我也能得到同样的结果。

首先,
apply
iterrows
都很慢,所以永远不要使用它们

在这种情况下,我通常会创建一对
向前
向后
指令:

forward = {'east': east,
           'west': west,
           'south': south}

backward = {x:k for k,v in forward.items() for x in v}
然后使用
map
进行更新。由于您希望基于两列进行更新,
fillna
将非常有用:

df1['Region'] = (df1['State'].map(backward)
                    .fillna(df1['City'].map(backward))
                    .fillna('other')
                )
给出:

  Last Name First Name  Code    Deparment           City State Region
0     SMITH        TOM    12     Research       NEW YORK    NY   east
1     JONES       DICK    34   Management         BOSTON    MA   east
2    WILSON      HARRY    56  Maintenance  SAN FRANCISCO    CA   west
3     DOYLE    MICHAEL    78    Marketing         DALLAS    TX  south
4  ANDERSON      KEVIN    90           IT        DETROIT    MI  other

您的问题在于如何使用
iterrows
。通常,您不应该修改正在迭代的内容。在这种情况下,
iterrows
正在创建数据的副本,因此实际上没有修改
df1
。复制可能会发生,也可能不会发生,这取决于具体情况,所以像这样的事情通常是您希望避免做的

您可以通过在处直接调用数据帧来确保它修改了原始数据帧:

for index, row in df1.iterrows(): 
    df1.at[index, 'Region'] = region(row['City'])
    if df1.at[index, 'Region'] == 'other': df1.at[index, 'Region'] = region(row['State'])

非常感谢。这完全奏效了,而且就你的观点而言,它更快,即使使用真实世界的数据。对我来说,倒着念是个新把戏。谢谢你的提示,这是个好提示。iterrows代码使用一个数据集而不使用另一个数据集,这让我很困惑,但我想这是不可预测的。当我使用它时,我通过删除“Code”列使df1数据集工作。关于它的某些东西可能偶然发现了数字数据?但无论哪种方式,选择的答案都可能是一种比最初使用iterrows更好的方法。谢谢你的帮助。@WilliamCollins没问题。改变某些东西可能会使它工作,但由于你做它的方式的不可预测性,你仍然不想这样做,因为它可能并不总是工作。我的回答是试图向你解释为什么你的代码不起作用。但是,另一种解决方案肯定更快,而且可能更好。