Pandas Boxplot with Groupby - построение векторных массивов в столбцах для каждой категории - PullRequest
0 голосов
/ 08 октября 2019
LTP,surface_distances
1.0,[3.        2.4494898 3.1622777  0.        0.        0.     9  ]
1.0,"[ 9.530573   9.530573   9.161782   8.731052   9.770159   9.615404
  9.480876   9.399235   9.371863   9.371863   9.371863   9.371863
  8.422484   8.330477   8.206197   9.068727   8.925962   8.839198
  8.54362    8.206197   7.919437   7.6890116  7.5201006  7.3780055
  7.130104   6.4887457  5.864883   5.2647395  9.591869   9.457006
]"
1.0,[0.        0.        0.     3.6649203 3.870587  4.065864 ]
1.0,"[ 7.95181    8.283971   7.7533436  7.1679688  7.4169073  7.854291
  8.127435   8.127435   7.619655   7.0959272  6.6085405  7.3821893
  7.8215146  8.032048   8.032048   8.063969   7.619655   7.1679688
  6.6498694  6.988916   7.3821893  7.8215146  8.         8.
  8.032048   8.127435   7.7533436  7.3798757  6.6498694  6.988916
  7.3821893  7.8215146  8.         8.         8.032048   8.127435
 ]"

Считать данные с помощью df = pd.read_clipboard(sep=',') Также добавлена ​​ссылка на данные: https://drive.google.com/file/d/1vfplqd04zs9Bigp9Vq8y6HqwDALe00NY/view?usp=sharing

Я бы хотел сгруппировать столбец df[distances] по df[LTP], который имеет толькоЗначения 0 и 1, представляющие 2 категории.

Я пытался:

df.boxplot(column=['distances'], by='LTP', ax=ax, return_type='axes')

И разделить на отдельный DataFrame с 2 столбцами.

dst_ltp = []
dst_no_ltp = []

for idx, row in df_final.iterrows():
    if row['LTP'] == 1:
        dst_no_ltp.append(row['distances'])
        dst_ltp.append(np.nan)
    if row['LTP'] == 0:
        dst_ltp.append(row['distances'])
        dst_no_ltp.append(np.nan)

new_df = pd.DataFrame(columns=['No LTP at 6m', 'LTP at 6m'], index=range(0, len(dst_ltp)))
new_df['No LTP at 6m'] = dst_no_ltp
new_df['LTP at 6m'] = dst_ltp
df1 = new_df.transpose() # transpose the matrix
fig, ax = plt.subplots(figsize=(10,8))
df1.boxplot(column=['No LTP at 6m', 'LTP at 6m'])

И

import seaborn as sns
sns.boxplot(data=pd.melt(df1))

Но я все еще не могу получить то, что хочу, что-то вроде этого:

enter image description here

Ответы [ 2 ]

1 голос
/ 08 октября 2019

Эти данные имеют проблемы:

Исправьте данные:

  • Использование converters={'surface_distance': eval} или ast.literal_eval не будет работать, потому что все строки данных неправильно заключены в [] на обоих концах.
  • Это полное решение, работающее с данными, представленными в файле Excel.
  • После исправления формата surface_distance используйте . explode(), для разделения списков
    • Эта функция работает на pandas.Series, поэтому установите индекс на LTP, чтобы каждому значению surface_distance был назначен соответствующий LTP значение.
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

def fix_my_data(x):
    x = x.replace('[', '').replace(']', '').strip().split(',')
    return [float(v.strip()) for v in x if v not in ['', ' ']]

# import the data
df = pd.read_excel('surface.xlsx')

# rename the column
df.rename(columns={'SurfaceDistances_Tumor2Ablation': 'surface_distance'}, inplace=True)

# create a valid list of numeric values
df.surface_distance = df.surface_distance.apply(fix_my_data)

# set index to LTP
df.set_index('LTP', inplace=True)

# pandas version 0.25 use explode to expand all lists
# update pandas if you're not on 0.25
df_sd = df.surface_distance.explode().rename_axis('LTP').reset_index(name='sd')

sns.boxplot(x='LTP', y='sd', data=df_sd)
plt.show()

enter image description here

1 голос
/ 08 октября 2019

Не уверен, что это именно то, что вам нужно.

Если вы хотите разбить списки, чтобы у каждого была соответствующая метка LTP, тогда это должно сработать.

import itertools

def flatten(a):
    return list(itertools.chain.from_iterable(a))    

# flatten the list of lists
res = df.groupby('LTP')['distances'].apply(flatten).reset_index()

# explode lists
res = (res['distances'].apply(pd.Series)
              .stack()
              .reset_index(level=1, drop=True)
              .to_frame('distances')).reset_index()
res.rename({'index':'LTP'}, axis=1, inplace=True)

# plot the new data
res.boxplot(column=['distances'], by='LTP', return_type='axes')

Выход

boxplot output

...