用户警告:Pandas 不允许通过新属性名称创建列
Posted
技术标签:
【中文标题】用户警告:Pandas 不允许通过新属性名称创建列【英文标题】:UserWarning: Pandas doesn't allow columns to be created via a new attribute name 【发布时间】:2019-02-07 08:06:15 【问题描述】:我被我的熊猫脚本困住了。
实际上,我正在处理两个 csv 文件(一个输入文件和另一个输出文件)。 我想复制两列的所有行并进行计算,然后将其复制到另一个数据框(输出文件)。
各栏目如下:
'lat', 'long','PHCount', 'latOffset_1', 'longOffset_1','PH_Lat_1', 'PH_Long_1', 'latOffset_2', 'longOffset_2', 'PH_Lat_2', 'PH_Long_2', 'latOffset_3', 'longOffset_3','PH_Lat_3', 'PH_Long_3', 'latOffset_4', 'longOffset_4','PH_Lat_4', 'PH_Long_4'.
我想获取 'lat' 和 'latOffset_1' 列,进行一些计算并将其放入我已经创建的另一个新列('PH_Lat_1')中。
我的功能是:
def calculate_latoffset(latoffset): #Calculating Lat offset.
a=(df2['lat']-(2*latoffset))
return a
主要代码:
for i in range(1,5):
print(i)
a='PH_lat_%d' % i
print (a)
b='latOffset_%d' % i
print (b)
df2.a = df2.apply(lambda x: calculate_latoffset(x[b]), axis=1)
由于列名仅相差 (1,2,3,4)。所以我想调用函数calculate_latoffset并一次性计算所有列(PH_Lat_1,PH_Lat_2,PH_Lat_3,PH_Lat_4)的所有行。
当使用上面的代码时,我得到了这个错误:
basic_conversion.py:46: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access
df2.a = df2.apply(lambda x: calculate_latoffset(x[b]), axis=1)
有可能吗? 请帮忙
【问题讨论】:
相关:***.com/q/41130255/2303761 【参考方案1】:只需使用df2['a']
而不是df2.a
【讨论】:
【参考方案2】:这是一个警告而不是错误,因此您的代码仍然可以运行,但可能不符合您的意图。
简短回答:要为 DataFrame 创建一个新列,永远不要使用属性访问,正确的方法是使用[]
或.loc
索引:
>>> df
a b
0 7 6
1 5 8
>>> df['c'] = df.a + df.b
>>> # OR
>>> df.loc[:, 'c'] = df.a + df.b
>>> df # c is an new added column
a b c
0 7 6 13
1 5 8 13
再解释一下,Seires 和 DataFrame 是 pandas 的核心类和数据结构,当然它们也是 Python 类,所以在涉及到 pandas DataFrame 和普通 Python 对象的属性访问时,会有一些细微的区别。但它是well documented,很容易理解。只需注意几点:
在 Python 中,用户可以使用属性访问将自己的数据属性动态添加到实例对象中。
>>> class Dog(object):
... pass
>>> dog = Dog()
>>> vars(dog)
>>> superdog = Dog()
>>> vars(superdog)
>>> dog.legs = 'I can run.'
>>> superdog.wings = 'I can fly.'
>>> vars(dog)
'legs': 'I can run.'
>>> vars(superdog)
'wings': 'I can fly.'
在pandas中,index和column与数据结构密切相关,你可以访问一个Series上的索引,一个列上的列DataFrame 作为属性。
>>> import pandas as pd
>>> import numpy as np
>>> data = np.random.randint(low=0, high=10, size=(2,2))
>>> df = pd.DataFrame(data, columns=['a', 'b'])
>>> df
a b
0 7 6
1 5 8
>>> vars(df)
'_is_copy': None,
'_data': BlockManager
Items: Index(['a', 'b'], dtype='object')
Axis 1: RangeIndex(start=0, stop=2, step=1)
IntBlock: slice(0, 2, 1), 2 x 2, dtype: int64,
'_item_cache':
但是,pandas 属性访问主要是为了方便读取和修改数据帧的系列或列的现有元素。
>>> df.a
0 7
1 5
Name: a, dtype: int64
>>> df.b = [1, 1]
>>> df
a b
0 7 1
1 5 1
而且,便利性是完整功能的折衷。例如。您可以使用列名['space bar', '1', 'loc', 'min', 'index']
创建一个 DataFrame 对象,但不能将它们作为属性访问,因为它们不是有效的 Python 标识符 1
、space bar
或与现有方法名称冲突。
>>> data = np.random.randint(0, 10, size=(2, 5))
>>> df_special_col_names = pd.DataFrame(data, columns=['space bar', '1', 'loc', 'min', 'index'])
>>> df_special_col_names
space bar 1 loc min index
0 4 4 4 8 9
1 3 0 1 2 3
在这些情况下,.loc
、.iloc
和 []
索引是 the defined way 以完全访问/操作索引和 Series 和 DataFrame 对象的列。
>>> df_special_col_names['space bar']
0 4
1 3
Name: space bar, dtype: int64
>>> df_special_col_names.loc[:, 'min']
0 8
1 2
Name: min, dtype: int64
>>> df_special_col_names.iloc[:, 1]
0 4
1 0
Name: 1, dtype: int64
关于主题,为DataFrame创建一个新列,如您所见,df.c = df.a + df.b
只是在核心数据结构旁边创建了一个新属性,所以从版本0.21.0
及更高版本,此行为将引发UserWarning
(不再沉默)。
>>> df
a b
0 7 1
1 5 1
>>> df.c = df.a + df.b
__main__:1: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access
>>> df['d'] = df.a + df.b
>>> df
a b d
0 7 1 8
1 5 1 6
>>> df.c
0 8
1 6
dtype: int64
>>> vars(df)
'_is_copy': None,
'_data':
BlockManager
Items: Index(['a', 'b', 'd'], dtype='object')
Axis 1: RangeIndex(start=0, stop=2, step=1)
IntBlock: slice(0, 2, 1), 2 x 2, dtype: int64
IntBlock: slice(2, 3, 1), 1 x 2, dtype: int64,
'_item_cache': ,
'c': 0 8
1 6
dtype: int64
最后,回到简答题。
【讨论】:
【参考方案3】:我能想到的解决方案是使用.loc
来获取列。你可以试试df.loc[:,a]
而不是df.a
。
Pandas 数据框列不能使用点方法创建,以避免与数据框属性的潜在冲突。希望这会有所帮助
【讨论】:
【参考方案4】:在df2.apply(lambda x: calculate_latoffset(x[b]), axis=1)
中,您正在创建一个 5 列数据框,并且您试图将值分配给单个字段。 df2[a] = calculate_latoffset(df2[b])
应该提供所需的输出。
【讨论】:
以上是关于用户警告:Pandas 不允许通过新属性名称创建列的主要内容,如果未能解决你的问题,请参考以下文章
pandas通过DatetimeProperties对象获取日期对象在所在周的周几星期几的名称信息(week name)并生成新的数据列计算不同星期名称下其它数据列的均值
如何从pandas Series类继承以简化Series类型的子集?
pandas将dataframe中的内容为列表(list)的数据列裂变拆分为多个新的数据列实战:拆分为多个新的数据列(并指定新数据列的名称)数据列中的列表(不等长)拆分为多个新的数据列产生NaN