【问题标题】:Splitting a string into list and converting the items to int将字符串拆分为列表并将项目转换为 int
【发布时间】:2019-03-25 05:09:47
【问题描述】:

我有一个 pandas 数据框,其中有一个 values 列,如下所示:

0       16 0
1    7 1 2 0
2          5
3          1
4         18

我想要创建另一列modified_values,其中包含拆分每个值后我将获得的所有不同数字的列表。新列将是这样的:

0       [16, 0]
1    [7, 1, 2, 0]
2          [5]
3          [1]
4         [18]

注意此列表中的值应为 int 而不是 strings

我知道的事情:

1) 我可以像这样以矢量化方式拆分列 df.values.str.split(" ")。这会给我列表,但列表中的对象将是字符串。我可以在上面添加另一个操作,例如 df.values.str.split(" ").apply(func to convert values to int) 但这不会被矢量化

2) 我可以直接这样做df['modified_values']= df['values'].apply(func that splits as well as converts to int)

第二个肯定会比第一个慢得多,但我想知道是否可以通过矢量化方式实现相同的目标。

【问题讨论】:

    标签: python python-3.x string pandas numpy


    【解决方案1】:

    不可能有原生的“矢量化”解决方案

    我之所以强调这一点,是因为假设pd.Series.str 方法是矢量化的,这是一个常见的错误。他们不是。它们以效率为代价提供便利和错误处理。 仅适用于干净的数据,例如没有 NaN 值,列表理解可能是您的最佳选择:

    df = pd.DataFrame({'A': ['16 0', '7 1 2 0', '5', '1', '18']})
    
    df['B'] = [list(map(int, i.split())) for i in df['A']]
    
    print(df)
    
             A             B
    0     16 0       [16, 0]
    1  7 1 2 0  [7, 1, 2, 0]
    2        5           [5]
    3        1           [1]
    4       18          [18]
    

    性能基准测试

    为了说明 pd.Series.str 的性能问题,您可以看到对于较大的数据帧,您传递给 Pandas 的操作越多,性能下降越多:

    df = pd.concat([df]*10000)
    
    %timeit [list(map(int, i.split())) for i in df['A']]            # 55.6 ms
    %timeit [list(map(int, i)) for i in df['A'].str.split()]        # 80.2 ms
    %timeit df['A'].str.split().apply(lambda x: list(map(int, x)))  # 93.6 ms
    

    list 作为 pd.Series 中的元素也是反熊猫

    described here一样,串联持有列表会产生2层指针,不推荐:

    不要这样做。 Pandas 从来没有被设计成以系列/列的形式保存列表。您可以炮制昂贵的解决方法,但这些不是 推荐。

    不推荐连续持有列表的主要原因是你输了 使用保存在连续内存块中的 NumPy 数组的矢量化功能。你的系列将是 object dtype,表示指针序列,很像list。你会输的 内存和性能方面的好处,以及访问优化的 Pandas 方法。

    另见What are the advantages of NumPy over regular Python lists? 支持 Pandas 的论点与支持 NumPy 的论点相同。

    【讨论】:

    • 很好地消除了 .str 方法在这里很好的误解,但也许值得一提的是,由此产生的结构也并不真正符合 pandas 标准?
    • @roganjosh,是的,说得好。这需要复制粘贴编辑:)
    • @jpp 感谢关于str的详细回答和急需的澄清
    • for 理解比 map 快。 Numba 比 NaN 快 250 倍。看我的回答。
    • @keiv.fly,很好的地方:嵌套列表组合!当然numba 结果在技术上是不同的(但实际上最好没有list)。
    【解决方案2】:

    双重for 理解比 jpp 答案中的 map 理解快 33%。 Numba 技巧比 jpp 的答案中的 map 理解要快 250 倍,但是您会得到一个带有浮点数和 nan 的 pandas DataFrame,而不是一系列列表。 Numba 包含在 Anaconda 中。

    基准测试:

    %timeit pd.DataFrame(nb_calc(df.A))            # numba trick       0.144 ms
    %timeit [int(x) for i in df['A'] for x in i.split()]            # 23.6   ms
    %timeit [list(map(int, i.split())) for i in df['A']]            # 35.6   ms
    %timeit [list(map(int, i)) for i in df['A'].str.split()]        # 50.9   ms
    %timeit df['A'].str.split().apply(lambda x: list(map(int, x)))  # 56.6   ms
    

    Numba 函数代码:

    @numba.jit(nopython=True, nogil=True)
    def str2int_nb(nb_a):
        n1 = nb_a.shape[0]
        n2 = nb_a.shape[1]
        res = np.empty(nb_a.shape)
        res[:] = np.nan
        j_res_max = 0
        for i in range(n1):
            j_res = 0
            s = 0
            for j in range(n2):
                x = nb_a[i,j]
                if x == 32:
                    res[i,j_res]=np.float64(s)
                    s=0
                    j_res+=1
                elif x == 0:
                    break
                else:
                    s=s*10+x-48
            res[i,j_res]=np.float64(s)
            if j_res>j_res_max:
                j_res_max = j_res
    
        return res[:,:j_res_max+1]
    
    def nb_calc(s):
        a_temp = s_a.values.astype("U")
        nb_a = a_temp.view("uint32").reshape(len(s_a),-1).astype(np.int8)
        str2int_nb(nb_a)
    

    Numba 不支持字符串。所以我首先转换为 int8 数组,然后才使用它。转换为 int8 实际上需要 3/4 的执行时间。

    我的 numba 函数的输出如下所示:

          0    1    2    3
    -----------------------
    0  16.0  0.0  NaN  NaN
    1   7.0  1.0  2.0  0.0
    2   5.0  NaN  NaN  NaN
    3   1.0  NaN  NaN  NaN
    4  18.0  NaN  NaN  NaN
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-14
      • 2010-10-29
      • 2016-02-29
      • 2013-09-20
      • 1970-01-01
      相关资源
      最近更新 更多