我有一堆数据帧,我试图切片并分配回原始名称。但我发现存在命名空间问题。以下是我所拥有的。
import pandas as pd
import numpy as np
df_a = pd.DataFrame(np.random.rand(14,2), columns = list('XY'))
df_b = pd.DataFrame(np.random.rand(14,2), columns = list('XY'))
mylist =[df_a, df_b]
def truncate_before(list_of_dfts, idx):
for dfts in list_of_dfts:
dfts = dfts[idx:]
print(dfts.head)
truncate_before(mylist, 11)
print(df_a)
在truncate_before函数的print语句中,它显示3行,对应于第11行,第12行和第13行。但最终的print语句显示第0到第13行。
因此,在函数之外,它将恢复为原始数据帧。我的印象是Python通过引用传递参数。我错过了什么?
答案 0 :(得分:1)
在truncate_before
:
def truncate_before(list_of_dfts, idx):
for dfts in list_of_dfts:
dfts = dfts[idx:]
print(dfts.head)
for-loop
创建一个本地变量dfts
,该变量引用list_of_dfts
中的DataFrame。但是
dfts = dfts[idx:]
将新值重新分配给dfts
。它不会更改list_of_dfts
中的DataFrame。
有关变量名称如何与值绑定的更好解释,请参阅Facts and myths about Python names and values,以及哪些操作更改值与将新值绑定到变量名称。
以下是一些替代方案:
修改地址列表
def truncate_before(list_of_dfts, idx):
list_of_dfts[:] = [dfts[idx:] for dfts in list_of_dfts]
for dfts in list_of_dfts:
print(dfts.head)
因为分配到list_of_dfts[:]
(调用list_of_dfts.__setitem__
)会更改list_of_dfts
的内容。
import numpy as np
import pandas as pd
df_a = pd.DataFrame(np.random.rand(14,2), columns = list('XY'))
df_b = pd.DataFrame(np.random.rand(14,2), columns = list('XY'))
mylist = [df_a, df_b]
def truncate_before(list_of_dfts, idx):
list_of_dfts[:] = [dfts[idx:] for dfts in list_of_dfts]
print(mylist[0])
truncate_before(mylist, 11)
print(mylist[0])
显示mylist[0]
已被截断。请注意,df_a
仍引用原始DataFrame。
返回列表并将mylist
或df_a, df_b
重新分配给结果
使用返回值可能无需就地修改mylist
。
要将全局变量df_a
,df_b
重新分配为新值,您可以制作
truncate_before
返回DataFrame列表,并重新分配df_a
和df_b
返回值:
def truncate_before(list_of_dfts, idx):
return [dfts[idx:] for dfts in list_of_dfts]
mylist = truncate_before(mylist, 11) # or
# df_a, df_b = truncate_before(mylist, 11) # or
# mylist = df_a, df_b = truncate_before(mylist, 11)
但请注意,通过mylist
和df_a
以及df_b
访问DataFrame可能并不好,因为如上例所示,值不会自动保持协调。使用mylist
就足够了。
将DataFrame方法与inplace参数一起使用,例如df.drop
dfts.drop
(inplace=True
}修改dfts
本身:
import numpy as np
import pandas as pd
df_a = pd.DataFrame(np.random.rand(14,2), columns = list('XY'))
df_b = pd.DataFrame(np.random.rand(14,2), columns = list('XY'))
mylist = [df_a, df_b]
def truncate_before(list_of_dfts, idx):
for dfts in list_of_dfts:
dfts.drop(dfts.index[:idx], inplace=True)
truncate_before(mylist, 11)
print(mylist[0])
print(df_a)
通过修改dfts
inplace,mylist
和 df_a
和df_b
中的值
同时改变。
请注意,dfts.drop
会根据索引标签值删除行。所以上面依赖
(假设)dfts.index
是唯一的。如果dfts.index
不是唯一的,
dfts.drop
行可能比idx
行多。例如,
df = pd.DataFrame([1,2], index=['A', 'A'])
df.drop(['A'], inplace=True)
删除两个行,使df
为空DataFrame。
另请注意Pandas核心开发人员关于使用inplace
:
我个人意见:我从不使用就地操作。语法更难 阅读并没有任何优势。
这可能是因为在幕后,dfts.drop
创建了一个新的数据框架
然后调用_update_inplace
私有方法将新数据分配给
旧的DataFrame:
def _update_inplace(self, result, verify_is_copy=True):
"""
replace self internals with result.
...
"""
self._reset_cache()
self._clear_item_cache()
self._data = getattr(result,'_data',result)
self._maybe_update_cacher(verify_is_copy=verify_is_copy)
由于无论如何都必须创建临时result
,因此“就地”操作与简单重新分配相比没有内存或性能优势。