Python:从数据框字符串列中提取维度数据并为每个列创建具有值的列

Posted

技术标签:

【中文标题】Python:从数据框字符串列中提取维度数据并为每个列创建具有值的列【英文标题】:Python: Extract dimension data from dataframe string column and create columns with values for each of them 【发布时间】:2019-10-19 03:57:29 【问题描述】:

嘿嘿,

我有一个包含 2 列的源文件:ID 和 all_dimensions。所有维度都是具有不同“键值”对的字符串,每个 id 都不相同。 我想制作键列标题并解析相应的值(如果存在于正确的单元格中)。

示例:

ID  all_dimensions
12  Height:2 cm,Volume: 4cl,Weight:100g
34  Length: 10cm, Height: 5 cm
56  Depth: 80cm
78  Weight: 2 kg, Length: 7 cm
90  Diameter: 4 cm, Volume: 50 cl

想要的结果:

ID  Height  Volume  Weight  Length  Depth  Diameter 
12  2 cm     4cl     100g      -      -        -
34  5 cm      -        -     10cm     -        -
56    -       -        -      -      80cm      -
78    -       -      2 kg    7 cm     -        -
90    -     50 cl     -       -      -        4 cm

我确实有超过 100 个维度,所以理想情况下,我想编写一个 for 循环或类似的东西,以不指定每个列标题(参见下面的代码示例) 我正在使用 Python 3.7.3 和 pandas 0.24.2。

我已经尝试了什么:

1) 我尝试将数据拆分为单独的列,但不确定如何继续将每个值分配到正确的标题中:

df.set_index('ID',inplace=True)
newdf = df["all_dimensions"].str.split(",|:",expand = True)

2) 使用初始 df,我使用“str.extract”创建新列(但随后我需要指定每个标题):

df['Volume']=df.all_dimensions.str.extract(r'Volume:([\w\s.]*)').fillna('')

3) 为了解决 2) 每个标题的问题,我创建了一个所有维度属性的列表,并考虑使用带有 for 循环的列表来提取值:

columns_list=df.all_dimensions.str.extract(r'^([\D]*):',expand=True).drop_duplicates()
columns_list=columns_list[0].str.strip().values.tolist()
for dimension in columns_list:
    df.dimension=df.all_dimensions.str.extract(r'dimension([\w\s.]*)').fillna('')

在这里,JupyterNB 给了我一个 UserWarning:“Pandas 不允许通过新属性名称创建列”并且 df 看起来和以前一样。

【问题讨论】:

感谢 WeNYoBen 编辑示例数据格式! 对于警告,将:trial.dimension 更改为 trial['dimension'] 【参考方案1】:

选项 1:我更喜欢拆分几次:

new_series = (df.set_index('ID')
                .all_dimensions
                .str.split(',', expand=True)
                .stack()
                .reset_index(level=-1, drop=True)
             )

# split second time for individual measurement
new_df = (new_series.str
                    .split(':', expand=True)
                    .reset_index()
                    )

# stripping off leading/trailing spaces
new_df[0] = new_df[0].str.strip()
new_df[1] = new_df[1].str.strip()

# unstack to get the desire table:
new_df.set_index(['ID', 0])[1].unstack()

选项 2:使用 split(',|:') 作为您尝试的方法:

# splitting
new_series = (df.set_index('ID')
                .all_dimensions
                .str.split(',|:', expand=True)
                .stack()
                .reset_index(level=-1, drop=True)
             )

# concat along axis=1 to get dataframe with two columns 
# new_df.columns = ('ID', 0, 1) where 0 is measurement name
new_df = (pd.concat((new_series[::2].str.strip(), 
                     new_series[1::2]), axis=1)
            .reset_index())

new_df.set_index(['ID', 0])[1].unstack()

输出

    Depth   Diameter    Height  Length  Volume  Weight
ID                      
12  NaN     NaN     2 cm    NaN     4cl     100g
34  NaN     NaN     5 cm    10cm    NaN     NaN
56  80cm    NaN     NaN     NaN     NaN     NaN
78  NaN     NaN     NaN     7 cm    NaN     2 kg
90  NaN     4 cm    NaN     NaN     50 cl   NaN

【讨论】:

【参考方案2】:

这是一个很难的问题,你的字符串需要是 split 并且你拆分后的每个项目都需要转换为 dict ,然后我们可以使用 DataFrame 构造函数重建这些列

d=[ [y.split(':')[0]:y.split(':')[1]for y in x.split(',')]for x in df.all_dimensions]
from collections import ChainMap
data = list(map(lambda x : dict(ChainMap(*x)),d))
s=pd.DataFrame(data)
df=pd.concat([df,s.groupby(s.columns.str.strip(),axis=1).first()],1)
df
Out[26]: 
   ID                       all_dimensions  Depth  ... Length  Volume Weight
0  12  Height:2 cm,Volume: 4cl,Weight:100g    NaN  ...    NaN     4cl   100g
1  34           Length: 10cm, Height: 5 cm    NaN  ...   10cm     NaN    NaN
2  56                          Depth: 80cm   80cm  ...    NaN     NaN    NaN
3  78           Weight: 2 kg, Length: 7 cm    NaN  ...   7 cm     NaN   2 kg
4  90        Diameter: 4 cm, Volume: 50 cl    NaN  ...    NaN   50 cl    NaN
[5 rows x 8 columns]

检查列

df['Height']
Out[28]: 
0     2 cm
1     5 cm
2      NaN
3      NaN
4      NaN
Name: Height, dtype: object

【讨论】:

你是如何加载数据的? 但是失败了,你用了特殊的分隔符吗? @Yuca 添加 sep '[' :-) @Erfan 你去添加str.strip 感谢大家的帮助,我要疯了! @WeNYoBen,我考虑了 dict 的东西并做了一些试验,但这并没有产生任何结果,因为我试图在 df 中做它并且不接受 dicts。

以上是关于Python:从数据框字符串列中提取维度数据并为每个列创建具有值的列的主要内容,如果未能解决你的问题,请参考以下文章

从pandas DataFrame中另一列中的位置给定的字符串列中提取字符[重复]

Python pandas 使用附加字符串列汇总数据框中的往返数据 [关闭]

从 pyspark 数据框字符串列中获取第一个数值到新列中

如何从字符串列中提取数字?

在pandas中提取包含多行和多列的JSON字符串列的部分

按字符串列的长度对数据帧进行排序[重复]