VGo*_*nPa 5 python apply multi-index pandas
我有一个MultiIndex pandas DataFrame,我想在其中的一个列中应用一个函数,并将结果分配给同一列.
In [1]:
import numpy as np
import pandas as pd
cols = ['One', 'Two', 'Three', 'Four', 'Five']
df = pd.DataFrame(np.array(list('ABCDEFGHIJKLMNO'), dtype='object').reshape(3,5), index = list('ABC'), columns=cols)
df.to_hdf('/tmp/test.h5', 'df')
df = pd.read_hdf('/tmp/test.h5', 'df')
df
Out[1]:
One Two Three Four Five
A A B C D E
B F G H I J
C K L M N O
3 rows × 5 columns
In [2]:
df.columns = pd.MultiIndex.from_arrays([list('UUULL'), ['One', 'Two', 'Three', 'Four', 'Five']])
df['L']['Five'] = df['L']['Five'].apply(lambda x: x.lower())
df
-c:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
Out[2]:
U L
One Two Three Four Five
A A B C D E
B F G H I J
C K L M N O
3 rows × 5 columns
In [3]:
df.columns = ['One', 'Two', 'Three', 'Four', 'Five']
df
Out[3]:
One Two Three Four Five
A A B C D E
B F G H I J
C K L M N O
3 rows × 5 columns
In [4]:
df['Five'] = df['Five'].apply(lambda x: x.upper())
df
Out[4]:
One Two Three Four Five
A A B C D E
B F G H I J
C K L M N O
3 rows × 5 columns
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,该函数未应用于列,我猜是因为我收到此警告:
-c:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
Run Code Online (Sandbox Code Playgroud)
奇怪的是,这个错误有时只会发生,我无法理解它何时发生,何时不发生.
我设法应用切片数据帧的函数.loc作为建议的警告:
In [5]:
df.columns = pd.MultiIndex.from_arrays([list('UUULL'), ['One', 'Two', 'Three', 'Four', 'Five']])
df.loc[:,('L','Five')] = df.loc[:,('L','Five')].apply(lambda x: x.lower())
df
Out[5]:
U L
One Two Three Four Five
A A B C D e
B F G H I j
C K L M N o
3 rows × 5 columns
Run Code Online (Sandbox Code Playgroud)
但是我想理解为什么在进行类似dict的切片(例如df['L']['Five'])而不是使用.loc切片时会发生这种行为.
注意:DataFrame来自一个没有多索引的HDF文件,这可能是奇怪行为的原因?
编辑:我正在使用Pandas v.0.13.1和NumPy v.1.8.0
df['L']['Five'] 选择值为"L"的级别0并返回一个DataFrame,然后选择"Five"列,返回所访问的系列.
在__getitem__一个数据框(存取[]),将尝试做正确的事,并给你正确的列.但是,这是链式索引,请参见此处
要访问一个多索引,使用所述元组表示法,('a','b')并且.loc这是明确的,例如df.loc[:,('a','b')].此外,这允许同时进行多轴索引(例如,行和列).
那么,当你进行链式索引和分配时,为什么这不起作用,例如df['L']['Five'] = value.
df['L']重新生成单索引的数据框.然后另一个python操作df_with_L['Five']选择'Five'发生的系列索引.我用另一个变量指出了这个.因为pandas将这些操作视为单独的事件(例如,单独调用__getitem__,因此必须将它们视为线性操作,它们会一个接一个地发生.
对比这个df.loc[:,('L','Five')] 将一个嵌套的元组传递(:,('L','Five'))给一个单独的调用__getitem__.这允许pandas将其作为单个实体来处理(并且因为它可以直接索引到帧中,因此fyi会快得多).
为什么这很重要?由于链式索引是2个调用,因此任何一个调用都可能因为切片的方式而返回数据的副本.因此,在设置此项时,您实际上是在设置副本,而不是原始帧.大熊猫不可能弄清楚这一点,因为它们是两个没有连接的独立python操作.
该SettingWithCopy警告是"启发式"检测它(这意味着它倾向于通过捕捉大多数情况下,仅仅是一个轻量级的检查).真实地解决这个问题很复杂.
该.loc操作是单个python操作,因此可以选择切片(仍然可以是副本),但允许pandas在修改后将该切片分配回帧中,从而按照您的想法设置值.
这是警告的原因.有时当您对数组进行切片时,您只需返回一个视图,这意味着您可以设置它没有问题.但是,即使单个 dtyped数组也可以生成副本(如果以特定方式切片).多重数据格式(意味着它说浮点数和对象数据)几乎总是会产生副本.是否创建视图取决于阵列的内存布局.
注意:这与数据源无关.