Python: извлечение данных измерений из строкового столбца dataframe и создание столбцов со значениями для каждого из них - PullRequest
6 голосов
/ 03 июня 2019

Hej,

У меня есть исходный файл с 2 столбцами: ID и all_dimensions.Все измерения - это строки с разными парами «ключ-значение», которые не совпадают для каждого идентификатора.Я хочу сделать заголовки столбцов ключей и проанализировать соответствующее значение, если оно существует в правой ячейке.

Пример:

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 дает мне предупреждение пользователя: «Pandas не позволяет создавать столбцы с помощью нового имени атрибута», и df выглядит так же, как и раньше.

Ответы [ 2 ]

4 голосов
/ 03 июня 2019

Вариант 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 голосов
/ 03 июня 2019

Это сложный вопрос, ваша строка должна быть 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
...