我有一堆数据框,我试图对其进行切片并将其分配回原始名称。但我发现存在名称空间问题。以下是我所拥有的。

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行。但是最终的打印语句显示第0至13行。

因此,在函数之外,它会恢复为原始数据帧。我的印象是Python通过引用传递参数。我想念什么?

最佳答案

truncate_before中:

def truncate_before(list_of_dfts, idx):
    for dfts in list_of_dfts:
        dfts = dfts[idx:]
        print(dfts.head)


for-loop创建一个引用dfts中的DataFrame的局部变量list_of_dfts。但

        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。



返回列表并将mylistdf_a, df_b重新分配给结果

使用返回值可能不需要就地修改mylist

要将全局变量df_adf_b重新分配给新值,您可以
truncate_before返回数据帧列表,然后重新分配df_adf_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)


但是请注意,同时通过mylistdf_adf_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)


通过就地修改dftsmylistdf_adf_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。

还请注意熊猫的核心开发人员有关使用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,因此与简单的重新分配相比,“就地”操作没有内存或性能上的好处。

关于python - 以编程方式将Pandas数据框切片,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35102908/

10-10 11:40