pandas获取某一列数据_Pandas某一列是列表,怎么展开呢?

本文介绍了如何将Pandas DataFrame中包含列表的列展开为多个行,对比了三种不同的实现方法:暴力遍历、使用apply和官方explode函数。详细展示了每种方法的代码实现,并通过性能测试展示了它们的效率差异。文章强调了简洁和高效在编程中的重要性,最后提到了Pandas官方的explode函数作为简洁高效的解决方案。
摘要由CSDN通过智能技术生成

问题来了

又是下午,昏昏欲睡。翻起了之前遇到的一个奇怪的需求,具体细节记不得了,只记得小姐姐当时一脸严肃的说,我这儿有一堆数据,某一列可能是列表,你把他们展开,一会儿给我。当时我还一脸懵逼,回味了很久才大致知道她啥意思。

大概就是这么一个dataframe:

b3d563d86dab0ab9a9ce6410c8e56ae8.png
变身前

把他进化成:

3d92c3569af7e9c9622e77e8cadaf506.png
进化后

当时想了想,这需求很简单啊,应该五分钟吧。于是,我又熟练的打开CSDN,在饱受一大群装逼犯和复制粘贴党的精神摧残后,还是决定关掉浏览器,先暴力解决一下(因为我很怕小姐姐口中的一会儿就是10分钟或者15分钟)。

导入一下,建造一下:

import pandas as pd
import numpy as np

dd = pd.DataFrame(
    {
        "A": [1, 2, 3, 4, 5],
        "B": ["a", "b", "c", "d", "e"],
        "C": [[1, 2], [3], np.nan, [], ["a", "b", "c"]],
    }
)
dd

这就是上面那个变身前的鬼数据。

  • 方法一

所以,咋暴力呢,大概就是对dataframe的每一行遍历一下,遇到list就for循环拼接一下:

def explode1(df, col):
    dftem1 = pd.DataFrame()
    for i in range(df.shape[0]):
        dftem = df.iloc[i].to_frame().T
        if isinstance(df.iloc[i][col], list):
            if len(df.iloc[i][col]) > 0:
                for j in range(len(df.iloc[i][col])):
                    dftem[col + "_"] = df.iloc[i][col][j]
                    dftem1 = pd.concat([dftem1, dftem])
            else:
                dftem1 = pd.concat([dftem1, dftem])
        else:
            dftem1 = pd.concat([dftem1, dftem])
    del dftem1[col]
    dftem1.rename(columns={col + "_": col}, inplace=True)
    return dftem1

在沉浸其中许久,写出了这么一坨,运行一下:

explode1(dd, "C") 

破费,交任务去了。

  • 方法二:

任务交上去了,我再回首我之前的写法,发现我不是很想看它。能不能优化一下呢?于是我找到了玩弄pandas多年的何同学,并向他展示了我刚刚写的高级写法。

“你先import this

“为啥?你就说能不能解决吧?”

“你这if套着for,for套着if,必需得学习一下python精神 ”

在我学习精神后,何同学给我发来这么一段:

def explode2(df, col):
    df[col] = df[col].apply(lambda x: [x] if not isinstance(x, list) else x)
    return df.drop(col, axis=1).join(
        pd.DataFrame(list(df[col])).stack().reset_index(level=1, drop=True).rename(col)
    ) 

这么简洁,这么优美,运行一下:

explode2(dd, "C")  

任重道远啊。

  • 方法三:

欣赏完何同学的写法,我陷入了沉思,在借鉴何同学和CSDN上的一个写法后,憋出了方法三:

def explode3(df, col):
    def cc(x):
        if isinstance(x, list):
            if len(x) >= 1:
                return x
            else:
                return np.nan
        else:
            return np.nan

    df[col] = dd[col].apply(cc)
    dt = df[pd.notnull(df.C)]
    return df.drop(columns=col).join(
        pd.DataFrame(
            {
                dt.columns[0]: dt[dt.columns[0]].repeat(dt[col].str.len()),
                col: np.concatenate(dt[col].values),
            }
        )[[col]]
    )

运行一下:

explode3(dd, "C")

破费。

那么看一下三个方法的运行效率吧:

%timeit explode1(dd, "C")
%timeit explode2(dd, "C")
%timeit explode3(dd, "C")

何同学还是高啊:

14.7 ms ± 742 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.87 ms ± 52.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.58 ms ± 148 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 

收拾收拾,睡午觉了。


  • 方法四

其实,官方有函数,刚在评论区看到:

dd.explode("C") 

以上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值