一次更改一个字符串中的字母(Pandas,Python3)

时间:2015-02-18 20:44:09

标签: python-3.x pandas

我在Pandas(DF)中有一个单词列表

Words
Shirt
Blouse
Sweater

我尝试做的是将这些字母中的某些字母换成我的字典中的字母一次一个字母

所以例如:

mydict = {"e":"q,w",
          "a":"z"}

会创建一个新列表,首先替换所有" e"在列表中一次一个,然后再次迭代替换所有" a"一次一个:

Words
Shirt
Blouse
Sweater
Blousq
Blousw
Swqater
Swwater
Sweatqr
Sweatwr
Swezter

我一直在寻找解决方案:Mass string replace in python?

并尝试了以下代码,但它更改了所有实例" e"而不是一次一个 - 任何帮助?:

mydict = {"e":"q,w"}
s = DF
for k, v in mydict.items():
    for j in v:
          s['Words'] = s["Words"].str.replace(k, j)
DF["Words"] = s

这似乎不起作用:

s = DF.replace({"Words": {"e": "q","w"}})

3 个答案:

答案 0 :(得分:1)

因为你需要一次替换一个字母,所以用熊猫解决这个问题听起来不是一个好问题,因为pandas是关于一次完成所有事情(矢量化操作)。我会将您的DataFrame转储到一个普通的旧列表中并使用列表操作:

words = DF.to_dict()["Words"].values()

for find, replace in reversed(sorted(mydict.items())):
    for word in words:
        occurences = word.count(find)
        if not occurences:
            print word
            continue
        start_index = 0
        for i in range(occurences):
            for replace_char in replace.split(","):
                modified_word = list(word)
                index = modified_word.index(find, start_index)
                modified_word[index] = replace_char
                modified_word = "".join(modified_word)
                print modified_word
            start_index = index + 1

给出了:

Words
Shirt
Blousq
Blousw
Swqater
Swwater
Sweatqr
Sweatwr
Words
Shirt
Blouse
Swezter

您可以将这些字词附加到列表中,然后重新创建一个DataFrame,而不是打印这些字词。

答案 1 :(得分:1)

这个答案与Brian的answer非常相似,但有点消毒,输出没有重复:

words = ["Words", "Shirt", "Blouse", "Sweater"]
md = {"e": "q,w", "a": "z"}
md = {k: v.split(',') for k, v in md.items()}

newwords = []

for word in words:
    newwords.append(word)
    for c in md:
        occ = word.count(c)
        pos = 0
        for _ in range(occ):
            pos = word.find(c, pos)
            for r in md[c]:
                tmp = word[:pos] + r + word[pos+1:]
                newwords.append(tmp)
            pos += 1

newwords的内容:

['Words', 'Shirt', 'Blouse', 'Blousq', 'Blousw', 'Sweater', 'Swqater', 'Swwater', 'Sweatqr', 'Sweatwr', 'Swezter']

Prettyprint:

Words
Shirt
Blouse
Blousq
Blousw
Sweater
Swqater
Swwater
Sweatqr
Sweatwr
Swezter

任何错误都是当前时间的结果。 ;)


更新(说明)

  

<强> TL;博士

     

主要思想是一个接一个地找到单词中出现的字符。对于每次出现,我们然后用replacement-char替换它(再次一个接一个)。替换后的单词将被添加到输出列表中。

我将尝试逐步解释所有内容:

words = ["Words", "Shirt", "Blouse", "Sweater"]
md = {"e": "q,w", "a": "z"}

好。你的基本输入。 :)

md = {k: v.split(',') for k, v in md.items()}

一种处理替换字典的简单方法。 md现在看起来像{"e": ["q", "w"], "a": ["z"]}。现在我们不必以不同的方式处理"q,w""z",但替换的步骤是相同的​​而忽略了这样一个事实:"a"只有一个替换字符。< / p>

newwords = []

用于存储输出的新列表。

for word in words:
    newwords.append(word)

我们必须为每个单词执行这些操作(我假设,原因很清楚)。我们还将世界直接附加到我们刚创建的输出列表(newwords)。

    for c in md:

ccharacter的缩写。因此,对于我们要替换的每个字符(md的所有键),我们执行以下操作。

        occ = word.count(c)
occ的{​​p> occurrences(是的。count也适合:P)。 word.count(c)返回c中字符/字符串word的出现次数。所以"Sweater".count("o") => 0"Sweater".count("e") => 2。 我们在此处使用此信息来了解,我们经常需要查看word以获取c的所有出现。

        pos = 0

我们在c中寻找word的初始位置。在下一个循环中使用。

        for _ in range(occ):

每次出现。由于连续数字对我们来说没有任何价值,我们&#34;丢弃&#34;它命名为_。此时c位于word。爱好。

            pos = word.find(c, pos)

喔。看。我们找到了c。 :) word.find(c, pos)返回cword的第一次出现的索引,从pos开始。一开始,这意味着从字符串开始=&gt;第一次出现c。但是通过此次调用,我们已经更新了pos。加上最后一行(pos += 1)会移动我们下一轮的搜索窗口,从上一次出现c开始。

            for r in md[c]:

现在你看,为什么我们之前更新了mc:我们现在可以轻松地对其进行迭代(旧的md[c].split(',')上的md也可以完成这项工作)。所以我们现在为每个替换字符做替换。

                tmp = word[:pos] + r + word[pos+1:]

实际更换。我们将其存储在tmp中(出于调试原因)。 word[:pos]向我们word提供c(独占c)的(当前)出现。 r是替代品。 word[pos+1:]添加剩下的字词(再次没有c)。

                newwords.append(tmp)

我们创建的新单词tmp现在进入我们的输出列表(newwords)。

            pos += 1

已经提到的pos调整为&#34;跳过c&#34;。


来自OP的其他问题: 是否有一种简单的方法来指示我想要替换的字符串中有多少个字母[(意思是一次多个)?

当然。 但我目前对如何实现这一点只有一个模糊的想法。当我睡着的时候,我会看着它。 ;)

words = ["Words", "Shirt", "Blouse", "Sweater", "multipleeee"]
md = {"e": "q,w", "a": "z"}
md = {k: v.split(',') for k, v in md.items()}
num = 2     # this is the number of replaces at a time.

newwords = []

for word in words:
    newwords.append(word)
    for char in md:
        for r in md[char]:
            pos = multiples = 0
            current_word = word
            while current_word.find(char, pos) != -1:
                pos = current_word.find(char, pos)
                current_word = current_word[:pos] + r + current_word[pos+1:]
                pos += 1
                multiples += 1
                if multiples == num:
                    newwords.append(current_word)
                    multiples = 0
                    current_word = word

newwords的内容:

['Words', 'Shirt', 'Blouse', 'Sweater', 'Swqatqr', 'Swwatwr', 'multipleeee', 'multiplqqee', 'multipleeqq', 'multiplwwee', 'multipleeww']

Prettyprint:

Words
Shirt
Blouse
Sweater
Swqatqr
Swwatwr
multipleeee
multiplqqee
multipleeqq
multiplwwee
multipleeww

我添加了multipleeee来证明替换是如何工作的:对于num = 2,它意味着前两个被替换,然后是接下来的两个。因此,更换部件没有交叉点。如果你想要['multiplqqee', 'multipleqqe', 'multipleeqq']这样的东西,你必须存储&#34;首先&#34;的位置。出现char。然后,您可以将pos恢复到if multiples == num: - 块中的该位置。

如果您有其他问题,请随时提出。 :)

答案 2 :(得分:0)

如果要循环,则需要在循环的每个循环更新s。你还需要循环v。

mydict = {"e":"q,w"}
s=deduped
for k, v in mydict.items():
     for j in v:
          s = s.replace(k, j)

然后将其重新分配给您的数据框:

df["Words"] = s

如果你可以把它写成一个接收1d数组的函数(list,numpy array etc ...),你可以使用df.apply将它应用到任何列,使用df.apply()