【问题标题】:Pandas: Insert variable substrings into column B from column A with help of dictionaryPandas:借助字典将变量子字符串从 A 列插入 B 列
【发布时间】:2015-09-06 13:20:23
【问题描述】:

我有这个pandas 数据框:

df = pd.DataFrame(["LONG AAPL 2X CBZ","SHORT GOOG 10X VON"], columns=["Name"])

我想在Name 列中识别"AAPL",将其传递给字典"AAPL":"Apple",然后将其插入到新列Description 的字符串中。

期望的输出:

Name                   Description
"LONG AAPL 2X CBZ"     "Tracks Apple with 2X leverage."
"SHORT GOOG 10X VON"   "Tracks Google with -10X leverage."

我遇到问题的部分是将变量子字符串输入另一个字符串"Tracks X with Y leverage."

如果我不必这样做,只需从 name 提取到 description 是可能的:

df["Description"] = df["Name"].str.extract(r"\s(\S+)\s").map({"AAPL":"Apple", "GOOG":"Google"})

或提取杠杆:

df["Description"] = df["Name"].str.extract(r"(\d+X)")

如果可能的话,我想使用regex 来提取变量,因为实际上我会做一些更详细的正则表达式,例如用于检索不同格式的乘数,例如X22x 等等。

注意:我可能需要设置另一列来告知杠杆是正还是负,并用它来决定是否在乘数前面附加"-"作为-10X leverage.

df["direction"] = df["name"].map(lambda x: "Long" if "LONG" in x else "Short" if "SHORT " in x else "Long")

Name                   Direction      Description
"LONG AAPL 2X CBZ"     "Long"         "Tracks Apple with 2X leverage."
"SHORT GOOG 10X VON"   "Short"        "Tracks Google with -10X leverage."

【问题讨论】:

  • 不应该是"LONG AAPL 2X CBZ"吗?
  • 谢谢,更正了DataFrame。

标签: python regex string pandas


【解决方案1】:

因为我们只关心前两个和倒数第二个子字符串:

df = pd.DataFrame(["LONG AAPL 2X CBZ", "SHORT GOOG 10X VON", "BULL AXP UN X3 VON","LONG AXP X3 VON"], columns=["Name"])

maps = {"AAPL": "Apple", "GOOG": "Google"}
signs = {"SHORT": "-"}

def split(i):
    spl = i.split()
    a, b, c = spl[0], spl[1], spl[-2]
    val = maps.get(b, b) # if name is not to be replaced keep original
    return "Tracks  {} with {}{} leverage".format(val, signs.get(a, ""), c)

df["Description"]  = df["Name"].map(split)

输出:

                 Name                        Description
0    LONG AAPL 2X CBZ     Tracks  Apple with 2X leverage
1  SHORT GOOG 10X VON  Tracks  Google with -10X leverage
2  BULL AXP UN X3 VON       Tracks  AXP with X3 leverage
3     LONG AXP X3 VON       Tracks  AXP with X3 leverage

仅拆分比使用正则表达式更有效:

In [33]: df2 = pd.concat([df]*10000)
In [34]: timeit  df2["Name"].map(split)
10 loops, best of 3: 57.5 ms per loop

In [35]: timeit f2(df2['Name'])
10 loops, best of 3: 168 ms per loop

如果你想添加更多的词来替换,只需将它们添加到地图中,与符号相同。

【讨论】:

  • 这不能正确处理问题中描述的杠杆符号。
  • @abeboparebop,我错过了那部分,但实现起来很简单
  • @PadraicCunningham 如果中间有更多文本怎么办?对于BULL AXP UN X3 VON,我得到:ValueError: too many values to unpack。不幸的是,这会发生很大的变化,这使得按空间分割变得困难。
  • @Winterflags,我们可以在 findall 中使用正则表达式,我将编辑,当您没有 AAPL 或 GOOG 的一行时,您希望发生什么?
  • 那我们又可以分裂了!名字总是一个词吗?
【解决方案2】:

您可以定义一个显式函数以应用于整个Name 系列。

df = pd.DataFrame(["LONG AAPL 2X CBZ","SHORT GOOG 10X VON"], columns=["Name"])

dmap = {"AAPL":"Apple", "GOOG":"Google"}
signmap = {"LONG": "", "SHORT": "-"}

def f(strseries):
    company = strseries.str.extract(r"\s(\S+)\s").map(dmap)
    leverage = strseries.str.extract(r"(\d+X)")
    sign = strseries.str.extract(r"(\S+)\s").map(signmap)
    return "Tracks " + company + " with " + sign + leverage + " leverage."

df['Description'] = f(df['Name'])

编辑:一次执行正则表达式提取可以将速度提高大约 2 倍,但会牺牲一些可读性。

def f2(strseries):
    sub_df = strseries.str.extract('(?P<sign>\S+)\s(?P<company>\S+)\s(?P<leverage>\d+X)')
    return "Tracks " + sub_df.company.map(dmap) + " with " + sub_df.sign.map(signmap) + sub_df.leverage + " leverage."

df['Description'] = f2(df['Name'])

【讨论】:

  • 我想使用这个解决方案,因为正则表达式在许多不同的情况下更加健壮。但是,如果dmap 中没有匹配项,我怎样才能将\s(\S+)\s 写成company?比如:val = maps.get(b, b); return "Tracks {} with {}{} leverage".format(val, signs.get(a, ""), c)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-19
  • 1970-01-01
  • 2021-03-20
  • 2018-08-07
  • 2018-10-27
  • 2019-07-09
相关资源
最近更新 更多