我需要修复在 pandas 循环中用单元格替换单元格值时出现的错误:
使用以下信息:
import pandas as pd
data = pd.read_csv('iEC7R76C.txt', sep=",")
data.head(2)
我想根据标题完成这一年,我得到这样的结果:
import re
cadena = data.title[0]
cadena
# 'Nicosia 2013 VulkÃ\xa0 Bianco (Etna)'
cadena = re.sub("\D", "", cadena)
cadena
# 2013
现在,如果我将位置 0 中的年份与该字符串匹配,它会更改它,但我收到此警报,我不知道它的含义,尽管我已经用谷歌搜索了足够多的内容,但我不明白:
data.anio[0] = cadena
data.head(2)
有了或多或少这样的东西,我可以浏览所有数据并完成它,但错误不断出现:
for i in range(0, len(data)):
cadena = data.title[i]
cadena = re.sub("\D", "", cadena)
if cadena != '':
if 1900 <= int(cadena) <= 2020:
data['anio'][i] = cadena
我把那个空的条件,因为有时标题没有年份,如果那一年在 1900 年和 2020 年之间,因为有些标题有例如“2001 年第 2 批葡萄酒的名称”,当我得到该字符串中的数字时,我返回20012
输入显示链接错误但我不明白的链接。
首先,错误是什么意思?
这是一个警告,当您执行以下操作时:
该值可能未分配。这是因为 select
dataframe[columna]
有时会返回对数据框实际列的引用,在这种情况下,后续访问[indice]
yes 将修改该列,但在其他情况下,它可能会dataframe[columna]
返回您的列的副本,在这种情况下,后续分配会修改该列复制,但不是原始数据框。熊猫似乎有时会返回一份副本,尽管我不清楚具体情况。我想这取决于您选择列时使用的表达式类型。无论如何,以防万一,它会警告您不要这样做。
那该怎么办?
引用单元格以更改其值的正确方法是:
这种访问单元格的方式将始终修改原始数据帧,因此不会产生警告。
在您的代码中,它将转换为:
更好的方法
只要有可能,在执行 pandas 操作时应避免循环,并将它们更改为在一行中作用于整个数据帧的向量操作(自然,pandas 内部会为其创建循环,但完成后它们会更有效率在 C 中比在 Python 中可以做的多)。
在这种情况下,您之前的所有循环都可以简化为一行:
列上的运算符
.str
返回一个对象向量,这些对象是列的内容,但具有向量方法,例如.extract()
(并且您还有更多,例如.startswith()
,.strip()
等)可以“一次”对所有对象起作用。在这种情况下,该方法
extract()
需要一个正则表达式,其中至少有一个捕获组指示您要提取的文本的哪一部分。在这种情况下,我要求一组 4 位数字。这样您就可以避免结果会包含不属于年份的额外数字的问题。更新
用户在评论中指出,除了查找的年份之外,某些行还包含其他四位数字,例如 1840。我的解决方案
.extract()
仅提取第一个匹配项,因此如果有两个匹配项,它将保留第一个匹配项。用户询问是否可以验证提取的年份是否在 1900 年到 2019 年之间,如果不是,则将结果留空。我有更好的解决方案。您可以细化正则表达式,而不是说“任何四位数字的序列”,而是说“数字 19 后跟两个数字,或数字 20 后跟 1 或 0,然后是另一个数字”。
表示这样的正则表达式是:
请注意使用
|
分隔两个所需选项。第一个是19\d\d
匹配上世纪的任何年份,第二个是20[01]\d
匹配前两位数字为“20”,下一个是1或0,最后一个是任何数字的年份,即 2000 年至 2019 年之间的年份。所以现在你会说:
多亏了这一点,在您有两个可能的四位数组的单元格中,例如“18401 Cellars 2013 Proprietary Red (Walla Walla Valley (OR))”,只有一个组将匹配正则表达式,这将是一个回来。
请注意,仍可能出现类似“19235 Cellars 2013 Proprietary Red (Walla Walla Valley (OR))”的情况,在这种情况下,与 1923 的匹配将是错误的。你可以用正则表达式更精确,强制你要找的那组数字是一个“整字”,也就是要找的数字两边都有一个“字边框”。所以“19235”不适合,因为在 3 之后没有单词边框。在正则表达式中,字符的
\b
意思就是(单词边界),所以下面的正则表达式会更安全地避免这样的情况: