Python: pandas 申请与地图
Python: pandas apply vs. map
我很难理解df.apply()
究竟是如何工作的。
我的问题如下:我有一个数据框df
。现在我想在几个列中搜索某些字符串。如果在任何列中找到该字符串,我想为找到该字符串的每一行添加一个“标签”(在新列中)。
我可以用 map
和 applymap
解决问题(见下文)。
但是,我希望更好的解决方案是使用 apply
,因为它将函数应用于整个列。
问题:使用apply
是不可能的吗?我的错误在哪里?
这是我使用 map
和 applymap
的解决方案。
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' object has no attribute 'str'
有什么建议吗?请注意,我实际应用程序中的搜索功能更复杂,需要正则表达式功能,这就是我首先使用 .str.contain
的原因。
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
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
另一种解决方案是使用 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
其他人给出了很好的替代方法。 这里有一种方法可以使用 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"。如果您只想在第一次找到字符串时退出,那么合并所有列可能会浪费时间,但这样做效率不高。您可以轻松地将函数更改为逐列查找并在找到匹配项时退出 (return true)。
我很难理解df.apply()
究竟是如何工作的。
我的问题如下:我有一个数据框df
。现在我想在几个列中搜索某些字符串。如果在任何列中找到该字符串,我想为找到该字符串的每一行添加一个“标签”(在新列中)。
我可以用 map
和 applymap
解决问题(见下文)。
但是,我希望更好的解决方案是使用 apply
,因为它将函数应用于整个列。
问题:使用apply
是不可能的吗?我的错误在哪里?
这是我使用 map
和 applymap
的解决方案。
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' object has no attribute 'str'
有什么建议吗?请注意,我实际应用程序中的搜索功能更复杂,需要正则表达式功能,这就是我首先使用 .str.contain
的原因。
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
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
另一种解决方案是使用 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
其他人给出了很好的替代方法。 这里有一种方法可以使用 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"。如果您只想在第一次找到字符串时退出,那么合并所有列可能会浪费时间,但这样做效率不高。您可以轻松地将函数更改为逐列查找并在找到匹配项时退出 (return true)。