如何拆分 Pandas 数据框中的一列元组?

2025-01-20 09:06:00
admin
原创
82
摘要:问题描述:我有一个 Pandas 数据框(这只是一小部分)>>> d1 y norm test y norm train len(y_train) len(y_test) \n0 64.904368 116.151232 1645 ...

问题描述:

我有一个 Pandas 数据框(这只是一小部分)

>>> d1
   y norm test  y norm train  len(y_train)  len(y_test)  \n0    64.904368    116.151232          1645          549
1    70.852681    112.639876          1645          549

                                    SVR RBF  \n0   (35.652207342877873, 22.95533537448393)
1  (39.563683797747622, 27.382483096332511)

                                        LCV  \n0  (19.365430594452338, 13.880062435173587)
1  (19.099614489458364, 14.018867136617146)

                                   RIDGE CV  \n0  (4.2907610988480362, 12.416745648065584)
1    (4.18864306788194, 12.980833914392477)

                                         RF  \n0   (9.9484841581029428, 16.46902345373697)
1  (10.139848213735391, 16.282141345406522)

                                           GB  \n0  (0.012816232716538605, 15.950164822266007)
1  (0.012814519804493328, 15.305745202851712)

                                             ET DATA
0  (0.00034337162272515505, 16.284800366214057)  j2m
1  (0.00024811554516431878, 15.556506191784194)  j2m
>>>

我想要拆分所有包含元组的列。例如,我想要将列替换LCV为列LCV-aLCV-b

我怎样才能做到这一点?


解决方案 1:

您可以通过pd.DataFrame(col.tolist())在该列上执行下列操作来做到这一点:

In [2]: df = pd.DataFrame({'a':[1,2], 'b':[(1,2), (3,4)]})

In [3]: df
Out[3]:
   a       b
0  1  (1, 2)
1  2  (3, 4)

In [4]: df['b'].tolist()
Out[4]: [(1, 2), (3, 4)]

In [5]: pd.DataFrame(df['b'].tolist(), index=df.index)
Out[5]:
   0  1
0  1  2
1  3  4

In [6]: df[['b1', 'b2']] = pd.DataFrame(df['b'].tolist(), index=df.index)

In [7]: df
Out[7]:
   a       b  b1  b2
0  1  (1, 2)   1   2
1  2  (3, 4)   3   4

注意:在早期版本中,建议使用此答案df['b'].apply(pd.Series)而不是pd.DataFrame(df['b'].tolist(), index=df.index)。 这也有效(因为它为每个元组创建一个系列,然后将其视为数据框的一行),但它比版本更慢/占用更多内存tolist,正如这里的其他答案所指出的那样(感谢denfromufa)。

解决方案 2:

对象str可用的访问器实际上是一个可迭代的。pandas.Series`dtype == object`

假设pandas.DataFrame df

df = pd.DataFrame(dict(col=[*zip('abcdefghij', range(10, 101, 10))]))

df

        col
0   (a, 10)
1   (b, 20)
2   (c, 30)
3   (d, 40)
4   (e, 50)
5   (f, 60)
6   (g, 70)
7   (h, 80)
8   (i, 90)
9  (j, 100)

我们可以测试它是否是可迭代的:

from collections import Iterable

isinstance(df.col.str, Iterable)

True

然后我们可以像其他可迭代对象一样对其进行分配:

var0, var1 = 'xy'
print(var0, var1)

x y

最简单的解决方案

因此我们可以在一行中分配两列:

df['a'], df['b'] = df.col.str

df

        col  a    b
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

更快的解决方案

稍微复杂一点,我们可以用它zip来创建一个类似的可迭代对象:

df['c'], df['d'] = zip(*df.col)

df

        col  a    b  c    d
0   (a, 10)  a   10  a   10
1   (b, 20)  b   20  b   20
2   (c, 30)  c   30  c   30
3   (d, 40)  d   40  d   40
4   (e, 50)  e   50  e   50
5   (f, 60)  f   60  f   60
6   (g, 70)  g   70  g   70
7   (h, 80)  h   80  h   80
8   (i, 90)  i   90  i   90
9  (j, 100)  j  100  j  100

排队

意思是,不要改变现有的df

这是可行的,因为它assign采用关键字参数,其中关键字是新的(或现有的)列名,值将是新列的值。您可以使用字典并将其解包,**然后将其用作关键字参数。

因此,这是一种巧妙的方法,分配一个名为的新列'g',它是可迭代对象中的第一个项df.col.str'h'也是可迭代对象中的第二个项df.col.str

df.assign(**dict(zip('gh', df.col.str)))

        col  g    h
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

list我的方法

使用现代列表理解和变量解包。
注意:也可以内联使用join

df.join(pd.DataFrame([*df.col], df.index, [*'ef']))

        col  g    h
0   (a, 10)  a   10
1   (b, 20)  b   20
2   (c, 30)  c   30
3   (d, 40)  d   40
4   (e, 50)  e   50
5   (f, 60)  f   60
6   (g, 70)  g   70
7   (h, 80)  h   80
8   (i, 90)  i   90
9  (j, 100)  j  100

变异版本将是

df[['e', 'f']] = pd.DataFrame([*df.col], df.index)

简单时间测试

短数据帧
使用上面定义的:

%timeit df.assign(**dict(zip('gh', df.col.str)))
%timeit df.assign(**dict(zip('gh', zip(*df.col))))
%timeit df.join(pd.DataFrame([*df.col], df.index, [*'gh']))

1.16 ms ± 21.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
635 µs ± 18.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
795 µs ± 42.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

长数据帧
大 10^3 倍

df = pd.concat([df] * 1000, ignore_index=True)

%timeit df.assign(**dict(zip('gh', df.col.str)))
%timeit df.assign(**dict(zip('gh', zip(*df.col))))
%timeit df.join(pd.DataFrame([*df.col], df.index, [*'gh']))

11.4 ms ± 1.53 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.1 ms ± 41.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.33 ms ± 35.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

解决方案 3:

在更大的数据集上,我发现.apply()比慢几个数量级pd.DataFrame(df['b'].values.tolist(), index=df.index)

这个性能问题已经在 GitHub 上关闭了,尽管我不同意这个决定:

性能问题 - 使用 pd.Series 与元组应用 #11615

它基于这个答案。

解决方案 4:

我认为更简单的方法是:

>>> import pandas as pd
>>> df = pd.DataFrame({'a':[1,2], 'b':[(1,2), (3,4)]})
>>> df
   a       b
0  1  (1, 2)
1  2  (3, 4)
>>> df['b_a'] = df['b'].str[0]
>>> df['b_b'] = df['b'].str[1]
>>> df
   a       b  b_a  b_b
0  1  (1, 2)    1    2
1  2  (3, 4)    3    4

解决方案 5:

第二种解决方案的警告是,

pd.DataFrame(df['b'].values.tolist())

是它将明确丢弃索引,并添加默认顺序索引,而接受的答案

apply(pd.Series)

不会,因为 apply 的结果将保留行索引。虽然最初保留了原始数组的顺序,但 Pandas 会尝试匹配两个数据框的索引。

如果您尝试将行设置为数字索引数组,这可能非常重要,Pandas 会自动尝试将新数组的索引与旧数组的索引进行匹配,并导致排序中的一些失真。

更好的混合解决方案是将原始数据框的索引设置到新的数据框上,即

pd.DataFrame(df['b'].values.tolist(), index=df.index)

这将保留使用第二种方法的速度,同时确保结果的顺序和索引得以保留。

解决方案 6:

@joris 答案的一个更简单版本是避免创建数据框而只是将列表分配给新列,例如:

df[['b1', 'b2']] = df['b'].tolist()

解决方案 7:

pandas.Series.str.extract是另一种选择,使用来自https://opendataportal-lasvegas.opendata.arcgis.com/datasets/restaurant-inspections-open-data/explore的数据

import pandas as pd
df = pd.read_csv('raw_data.csv', low_memory=False)
df[['latitude', 'longitude']] = df['Location_1'].str.extract(pat = '(-?d+.d+),s*(-?d+.d+)')
df.to_csv('result.csv')
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用