将DataFrame 的每一列的列标题和每一行元素打包成一个元组 *zip
  X5zJxoD00Cah 2023年11月22日 25 0

将 DataFrame 的每一列的(列标题和每一行元素)打包成一个元组

将 DataFrame 的(列标题)和

    def fun_zip(
        self,
        df_arg=pd.DataFrame(),
        bool_arg=False
    ):
        # 每列元素打包
        zipped = zip(*[df_arg.iloc[i] for i in range(df_arg.shape[0])])
        # 是否包含标题
        if bool_arg:
            list_zip = [(col_name, *row) for col_name, row in zip(df_arg.columns, zipped)]
        else:
            list_zip = [tuple(row) for row in zipped]
        return list_zip

这段代码的目的是将一个 DataFrame 的每一列打包成一个元组,然后返回这些元组的列表。如果 bool_argTrue,则每个元组的第一个元素是列名。

这段代码已经很好地完成了这个任务,但是有一些地方可以进行优化:

  1. 默认参数:在函数定义中,尽量避免使用可变的默认参数,比如这里的 df_arg=pd.DataFrame()。这是因为默认参数在 Python 中只会被评估一次,如果你对默认参数进行了修改,那么这个修改会在下次调用函数时保留。所以,更好的做法是将默认参数设置为 None,然后在函数体中检查这个参数是否为 None,如果是,则赋予其默认值。
  2. 使用 itertools.zip_longest:在你的代码中,你使用了 zip 函数来打包每一列。然而,如果 DataFrame 的列长度不一致,zip 函数会忽略多出来的元素。为了避免这种情况,你可以使用 itertools.zip_longest 函数,它会用 None 来填充短的列。
  3. 使用 DataFrame.itertuples:Pandas 提供了一个 itertuples 方法,可以更高效地迭代 DataFrame 的行。你可以使用这个方法来替代 zip(*[df_arg.iloc[i] for i in range(df_arg.shape[0])])

考虑到以上的优化建议,你的代码可以改写成如下形式:

from itertools import zip_longest

def fun_zip(
    self,
    df_arg=None,
    bool_arg=False
):
    if df_arg is None:
        df_arg = pd.DataFrame()

    # 每列元素打包
    zipped = zip_longest(*df_arg.itertuples(index=False, name=None))
    # 是否包含标题
    if bool_arg:
        list_zip = [(col_name, *row) for col_name, row in zip(df_arg.columns, zipped)]
    else:
        list_zip = [row for row in zipped]
    return list_zip

在你提供的代码 zipped = zip_longest(*df_arg.itertuples(index=False, name=None)) 中,zip_longest 函数会返回一个迭代器,每个元素都是一个元组,元组中的元素对应于 df_arg 的每一行。

  • [tuple(row) for row in zipped]:这段代码会将 zipped 中的每个元素(已经是元组)转换为元组,所以这里的 tuple(row) 实际上没有改变 row 的数据类型。这意味着,最后得到的是一个元组的列表,列表中的每个元组对应于 df_arg 的一行。
  • [row for row in zipped]:这段代码会直接将 zipped 中的元素(元组)放入列表中,不进行任何类型转换。这意味着,最后得到的也是一个元组的列表,列表中的每个元组对应于 df_arg 的一行。

所以,在这个特定的情况下,[tuple(row) for row in zipped][row for row in zipped] 的结果是一样的,因为 zipped 中的元素已经是元组。


在 Python 中,self 是一个约定俗成的名字,用于指代实例本身。在类的方法中,我们通常将 self 作为第一个参数,以便可以在方法中引用实例的属性和其他方法。

然而,并不是所有的函数参数都需要前面加 self。只有当你需要在方法中访问或修改实例的属性时,才需要使用 self。如果一个变量只在方法内部使用,那么就不需要 self

例如,以下是一个类的定义,其中 self.name 是一个实例属性,而 greeting 只是 say_hello 方法的一个局部变量:

class Person:
    def __init__(self, name):
        self.name = name

    def say_hello(self):
        greeting = "Hello, " + self.name
        print(greeting)

在这个例子中,self.name 是需要 self 的,因为它是一个实例属性,我们希望在类的其他方法中也能访问到它。而 greeting 只在 say_hello 方法中使用,所以它不需要 self

总的来说,是否在变量前加 self,取决于你是否希望这个变量在整个实例中都可见。如果是,那么就需要 self;如果只是方法内部的临时变量,那么就不需要 self


你遇到的问题是由于 Python 的列表推导式(list comprehension)中不支持解包(unpacking)。在你的代码 [*row for row in zipped] 中,*row 是试图解包 row,但是在列表推导式中这是不被允许的。

如果你想要得到一个列表,其中每个元素都是 zipped 中的一个元组,你可以直接使用 list(zipped),或者使用列表推导式 [row for row in zipped]。这两种方式都可以得到相同的结果。

如果你想要将 zipped 中的所有元素解包成一个列表,你可以在列表推导式外部进行解包,像这样:[*zipped]。这样,你会得到一个列表,其中包含了 zipped 中所有元组的所有元素。



这段代码的目的是将 DataFrame 的每一列打包成一个元组,然后返回这些元组的列表。如果 bool_argTrue,则每个元组的第一个元素是列名。



检查并优化
    def fun_zip(
        self,
        df_arg=None,
        bool_arg=True
    ):
        if df_arg is None:
            df_arg = pd.DataFrame()

        # 每列元素打包
        zipped = zip_longest(*df_arg.itertuples(index=False, name=None))
        list_zip = list(zipped)
        # 是否包含标题
        if bool_arg:
            list_zip = [(col_name, *row) for col_name, row in zip(df_arg.columns, zipped)]
        return list_zip

这段代码已经很好地完成了这个任务,但是有一点需要注意:

在你的代码中,你先创建了 list_zip,然后在 if bool_arg: 的条件下可能会覆盖它。但是,如果 bool_argTruezip_longest(*df_arg.itertuples(index=False, name=None)) 这个迭代器在创建 list_zip 时已经被耗尽,所以在 zip(df_arg.columns, zipped) 中,zipped 是空的。这意味着,如果 bool_argTrue,你的函数会返回一个空列表。

为了解决这个问题,你可以在 if bool_arg: 的条件下重新创建 zipped,像这样:

from itertools import zip_longest
import pandas as pd

def fun_zip(
    self,
    df_arg=None,
    bool_arg=True
):
    if df_arg is None:
        df_arg = pd.DataFrame()

    # 每列元素打包
    zipped = zip_longest(*df_arg.itertuples(index=False, name=None))
    # 是否包含标题
    if bool_arg:
        list_zip = [(col_name, *row) for col_name, row in zip(df_arg.columns, list(zipped))]
    else:
        list_zip = list(zipped)
    return list_zip

这样,无论 bool_arg 的值是什么,你的函数都会返回正确的结果。希望这个建议对你有所帮助!


在 Python 中,迭代器是一个可以记住遍历的位置的对象。迭代器从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不像列表或者数组,迭代器不会一次性把所有元素加载到内存,而是需要时才生成元素。

迭代器(比如你在代码中使用的 zip_longest 函数返回的对象)是一次性的。这意味着迭代器中的元素在被访问后就会被丢弃,这就是所谓的 “迭代器被耗尽”。如果你试图再次从同一个迭代器中获取元素,你会发现它已经没有元素了,因为它们已经被访问并丢弃了。

例如,考虑以下代码:

my_list = [1, 2, 3]
my_iter = iter(my_list)

for item in my_iter:
    print(item)

for item in my_iter:
    print(item)

在这个例子中,第一个 for 循环会打印出列表中的所有元素。但是第二个 for 循环不会打印任何东西,因为迭代器已经被耗尽,所有的元素都已经被访问并丢弃了。

所以,如果你想要再次访问迭代器中的元素,你需要重新创建迭代器。希望这个解释能帮助你理解!


df.itertuples() 是 pandas DataFrame 的一个方法,它会返回一个迭代器,迭代器中的每个元素都是一个元组,元组中的元素对应于 DataFrame 的一行¹²。

这个方法有两个参数:

  • index:默认为 True。如果为 True,则返回的元组的第一个元素是索引¹。
  • name:默认为 'Pandas'。这个参数可以设置返回的 namedtuple 的名称。如果为 None,则返回普通的元组¹。

例如,假设我们有一个 DataFrame df

import pandas as pd

df = pd.DataFrame({
    'num_legs': [4, 2],
    'num_wings': [0, 2]
}, index=['dog', 'hawk'])

我们可以使用 itertuples() 来迭代 DataFrame 的行:

for row in df.itertuples():
    print(row)

输出:

Pandas(Index='dog', num_legs=4, num_wings=0)
Pandas(Index='hawk', num_legs=2, num_wings=2)

如果我们设置 index=False,则可以去掉索引:

for row in df.itertuples(index=False):
    print(row)

输出:

Pandas(num_legs=4, num_wings=0)
Pandas(num_legs=2, num_wings=2)

希望这个解释能帮助你理解!

(1) pandas.DataFrame.itertuples — pandas 2.1.3 documentation. https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.itertuples.html.

(2) Pandas DataFrame itertuples() Method - W3Schools. https://www.w3schools.com/python/pandas/ref_df_itertuples.asp.

(3) iterate over pandas dataframe using itertuples - Stack Overflow. https://stackoverflow.com/questions/43221208/iterate-over-pandas-dataframe-using-itertuples.

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月22日 0

暂无评论

推荐阅读
  X5zJxoD00Cah   2023年12月11日   26   0   0 知乎Python迭代器
X5zJxoD00Cah