【问题标题】:Python: pandas apply vs. mapPython:熊猫应用与地图
【发布时间】:2017-02-11 11:52:33
【问题描述】:

我很难理解df.apply()究竟是如何工作的。

我的问题如下:我有一个数据框df。现在我想在几列中搜索某些字符串。如果在任何列中找到该字符串,我想为找到该字符串的每一行添加一个“标签”(在新列中)。

我可以用mapapplymap 解决这个问题(见下文)。

但是,我希望更好的解决方案是使用 apply,因为它将函数应用于整个列。

问题:这不能使用apply 吗?我的错误在哪里?

这是我使用mapapplymap 的解决方案。

df = pd.DataFrame([list("ABCDZ"),list("EAGHY"), list("IJKLA")], columns = ["h1","h2","h3","h4", "h5"])

使用map的解决方案

def setlabel_func(column):
    return df[column].str.contains("A")

mask = sum(map(setlabel_func, ["h1","h5"]))
df.ix[mask==1,"New Column"] = "Label"

使用applymap的解决方案

mask = df[["h1","h5"]].applymap(lambda el: True if re.match("A",el) else False).T.any()
df.ix[mask == True, "New Column"] = "Label"

对于apply我不知道如何将两列传递给函数/或者根本不了解机制;-)

def setlabel_func(column):
    return df[column].str.contains("A")

df.apply(setlabel_func(["h1","h5"]),axis = 1)

上面给了我警报。

'DataFrame' 对象没有属性 'str'

有什么建议吗?请注意,我的实际应用程序中的搜索功能更复杂,需要一个正则表达式函数,这就是我首先使用.str.contain 的原因。

【问题讨论】:

  • 你的预期输出是什么?
  • 您好约翰,感谢您的回复。我的预期输出是 mapapplymap 返回的解决方案。对不起,我不知道如何在这里粘贴我的输出?你是怎么做到的?

标签: python pandas apply


【解决方案1】:

另一种解决方案是使用DataFrame.any 每行至少获得一个True

print (df[['h1', 'h5']].apply(lambda x: x.str.contains('A')))
      h1     h5
0   True  False
1  False  False
2  False   True

print (df[['h1', 'h5']].apply(lambda x: x.str.contains('A')).any(1))
0     True
1    False
2     True
dtype: bool

df['new'] = np.where(df[['h1','h5']].apply(lambda x: x.str.contains('A')).any(1),
                     'Label', '')

print (df)
  h1 h2 h3 h4 h5    new
0  A  B  C  D  Z  Label
1  E  A  G  H  Y       
2  I  J  K  L  A  Label

mask = df[['h1', 'h5']].apply(lambda x: x.str.contains('A')).any(1)
df.loc[mask, 'New'] = 'Label'
print (df)
  h1 h2 h3 h4 h5    New
0  A  B  C  D  Z  Label
1  E  A  G  H  Y    NaN
2  I  J  K  L  A  Label

【讨论】:

  • 感谢您的快速回复。 np.where 对我来说是新的。这将显着改进我以前的所有代码:-)
【解决方案2】:

pd.DataFrame.apply 遍历每一列,将该列作为pd.Series 传递给正在应用的函数。在您的情况下,您尝试应用的功能不适用于apply

这样做是为了让你的想法发挥作用

mask = df[['h1', 'h5']].apply(lambda x: x.str.contains('A').any(), 1)
df.loc[mask, 'New Column'] = 'Label'

  h1 h2 h3 h4 h5 New Column
0  A  B  C  D  Z      Label
1  E  A  G  H  Y        NaN
2  I  J  K  L  A      Label

​

【讨论】:

  • 太棒了。工作得很好。感谢您的快速回复。
【解决方案3】:

IIUC 你可以这样做:

In [23]: df['new'] = np.where(df[['h1','h5']].apply(lambda x: x.str.contains('A'))
                                             .sum(1) > 0,
                              'Label', '')

In [24]: df
Out[24]:
  h1 h2 h3 h4 h5    new
0  A  B  C  D  Z  Label
1  E  A  G  H  Y
2  I  J  K  L  A  Label

【讨论】:

  • 感谢您的快速回复。 np.where 对我来说是新的。这将显着改进我以前的所有代码:-)
  • @FredMaster,很高兴我能帮上忙 :-)
【解决方案4】:

其他人提供了很好的替代方法。 这是一种使用 apply 'row wise' (axis=1) 的方法,可以让您的新列指示一堆列存在“A”。

如果您传递了一行,您可以将字符串连接成一个大字符串,然后使用字符串比较(“in”),如下所示。在这里,我梳理了所有列,但您可以轻松地仅使用 H1 和 h5 来完成。

df = pd.DataFrame([list("ABCDZ"),list("EAGHY"), list("IJKLA")], columns = ["h1","h2","h3","h4", "h5"])

def dothat(row):
    sep = ""
    return "A" in sep.join(row['h1':'h5'])
df['NewColumn'] = df.apply(dothat,axis=1)

这只是将每一行压缩成一个字符串(例如 ABCDZ)并查找“A”。这不是那么有效,但如果您只想在第一次找到字符串时退出,那么组合所有列可能会浪费时间。您可以轻松地将函数更改为逐列查看并在找到命中时退出(返回 true)。

【讨论】:

    猜你喜欢
    • 2018-05-28
    • 2017-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    相关资源
    最近更新 更多