pandas 如何确定panda Dataframe 列中列表的长度

cld4siwp  于 2023-03-21  发布在  其他
关注(0)|答案(3)|浏览(199)

如何确定列中列表的长度而不进行迭代?
我有这样一个 Dataframe :

CreationDate
2013-12-22 15:25:02                  [ubuntu, mac-osx, syslinux]
2009-12-14 14:29:32  [ubuntu, mod-rewrite, laconica, apache-2.2]
2013-12-22 15:42:00               [ubuntu, nat, squid, mikrotik]

我正在计算CreationDate列中列表的长度,并创建一个新的Length列,如下所示:

df['Length'] = df.CreationDate.apply(lambda x: len(x))

这就给了我这个:

CreationDate  Length
2013-12-22 15:25:02                  [ubuntu, mac-osx, syslinux]       3
2009-12-14 14:29:32  [ubuntu, mod-rewrite, laconica, apache-2.2]       4
2013-12-22 15:42:00               [ubuntu, nat, squid, mikrotik]       4

有没有更像Python的方法?

wf82jlnq

wf82jlnq1#

您还可以将str访问器用于某些列表操作。

df['CreationDate'].str.len()

返回每个列表的长度。参见str.len的文档。

df['Length'] = df['CreationDate'].str.len()
df
Out: 
                                                    CreationDate  Length
2013-12-22 15:25:02                  [ubuntu, mac-osx, syslinux]       3
2009-12-14 14:29:32  [ubuntu, mod-rewrite, laconica, apache-2.2]       4
2013-12-22 15:42:00               [ubuntu, nat, squid, mikrotik]       4

对于这些操作,普通Python通常更快。不过panda处理NaN。下面是时间安排:

ser = pd.Series([random.sample(string.ascii_letters, 
                               random.randint(1, 20)) for _ in range(10**6)])

%timeit ser.apply(lambda x: len(x))
1 loop, best of 3: 425 ms per loop

%timeit ser.str.len()
1 loop, best of 3: 248 ms per loop

%timeit [len(x) for x in ser]
10 loops, best of 3: 84 ms per loop

%timeit pd.Series([len(x) for x in ser], index=ser.index)
1 loop, best of 3: 236 ms per loop
vecaoik1

vecaoik12#

import pandas as pd

data = {'os': [['ubuntu', 'mac-osx', 'syslinux'], ['ubuntu', 'mod-rewrite', 'laconica', 'apache-2.2'], ['ubuntu', 'nat', 'squid', 'mikrotik']]}
index = ['2013-12-22 15:25:02', '2009-12-14 14:29:32', '2013-12-22 15:42:00']

df = pd.DataFrame(data, index)

# create Length column
df['Length'] = df.os.map(len)

# display(df)
                                                              os  Length
2013-12-22 15:25:02                  [ubuntu, mac-osx, syslinux]       3
2009-12-14 14:29:32  [ubuntu, mod-rewrite, laconica, apache-2.2]       4
2013-12-22 15:42:00               [ubuntu, nat, squid, mikrotik]       4

∮ ∮ ∮ ∮ %timeit

import pandas as pd
import random
import string

random.seed(365)

ser = pd.Series([random.sample(string.ascii_letters, random.randint(1, 20)) for _ in range(10**6)])

%timeit ser.str.len()
252 ms ± 12.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit ser.map(len)
220 ms ± 7.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit ser.apply(len)
222 ms ± 8.31 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
snz8szmq

snz8szmq3#

转换为列表和map函数

Pandas Dataframe 列并不意味着存储列表、元组等集合,因为实际上没有任何优化方法可以在这些列上工作,所以当 Dataframe 包含这样的项时,通常将列转换为Python列表并操作列表会更有效。
此外,如果需要对列表中的每个项调用一个函数(特别是像len()这样的内置函数),通常使用map这个函数比在循环中调用它更快。

mylist = df['CreationDate'].tolist()
df['Length'] = list(map(len, mylist))
句柄NaN

str.len()的优点是它可以处理NaN,但是try-except的自定义函数应该可以填补这个空白。

def nanlen(x):
    try:
        return len(x)
    except TypeError:
        return float('nan')
    
df['Length'] = list(map(nanlen, mylist))
运行时基准测试

本质上,在列表上Maplen比在Series上循环快大约2.5倍,对于大帧,循环又比pd.Series.str.len快2.5倍。

用于生成上图的代码:

import pandas as pd
import random, string, perfplot
random.seed(365)

perfplot.plot(
    setup=lambda n: pd.Series([random.sample(string.ascii_letters, random.randint(1, 20)) for _ in range(n)]),
    kernels=[lambda ser: ser.str.len(), lambda ser: ser.map(len), lambda ser: list(map(len, ser.tolist())), lambda ser: [len(x) for x in ser]],
    labels=["ser.str.len()", "ser.map(len)", "list(map(len, ser.tolist()))", "[len(x) for x in ser]"],
    n_range=[2**k for k in range(21)],
    xlabel='Length of dataframe',
    equality_check=lambda x,y: x.eq(y).all()
)

相关问题