#python #pandas #csv
#python #pandas #csv
Вопрос:
У меня есть файл CSV, содержащий информацию о лекарстве (название) и дозе для некоторых пациентов (id), которые принимают.
Файл CSV структурирован следующим образом:
name, id, dose
ator, 034, 20
ator, 034, 30
para, 034, 30
mar, 035, 20
mar, 034, 10
Цель состоит в том, чтобы разобрать его в «длинный» формат со следующими столбцами: «идентификатор», «таблица» (имя таблицы, указанное в коде), поле (т. Е. имя, доза), значение (т. Е. значение, например, name или dose). До сих пор мне удавалось форматировать исходную структуру CSV в это.
Но я также хочу столбец «count», который содержит приращение лекарств, принимаемых каждым пациентом. Например, пациент с идентификатором 034 принимает три лекарства (ator, para и mar), что соответствует количеству 1, 2 и 3. Таким образом, желаемый результат следующий:
id,table,field,count,value
034, meds, name, 1, ator
034, meds, name, 1, ator
034, meds, name, 2, para
035, meds, name, 1, mar
034, meds, name, 3, mar
034, meds, dose, 1, 20
034, meds, dose, 1, 30
034, meds, dose, 2, 30
035, meds, dose, 1, 20
034, meds, dose, 3, 10
Каждый раз, когда пациент (т. Е. идентификатор) получает новое лекарство (т. Е. имя), «количество» должно представлять, какое лекарство соответствует, например, дозе позже в таблице.
Но я борюсь с получением такого столбца count.
Я пытался добавить столбец count во фрейм данных с помощью моего кода (пожалуйста, смотрите ниже), но безуспешно.
Любая помощь по созданию этого столбца была бы отличной!
import pandas as pd
# load the data into a pandas table:
file = '~/data/meds.csv'
df = pd.read_table(file, delimiter=',')
#### CANNOT GET THIS PART TO WORK: #####
count = []
for index, row in df.iterrows():
count.append(df[(df['id'] == row['id']) amp; (df['name'] < row['name'])].shape[0])
df['count'] = count
########################################
# convert data frame into the long format
df = pd.melt(df, id_vars=['id', 'count'], var_name='field', value_name='value')
# Change all NaNs to None
df = df.where((pd.notnull(df)), None)
# creating new column with table name
table = []
df['table'] = 'meds'
# save to file:
df.to_csv('~/data/meds_out.csv', encoding='utf-8')
Комментарии:
1. Кажется,
['study_id', 'recid']
столбцов нет во входных данных, вы можете добавить это?2. Ах, извините, я изменил study_id на id, чтобы упростить код для этой цели. Я исправлю это во фрагменте кода.
3. Да, значит, решение работает?
4. Вроде того, я бы хотел, чтобы он учитывал лекарства как количество, а не идентификаторы (т. Е. пациент может принимать одно и то же лекарство несколько раз). Но я думаю, это тоже сработает, просто не так, как я себе представлял 🙂 Спасибо.
5. хммм, работаю над этим, дай мне немного времени
Ответ №1:
Используйте melt
with GroupBy.cumcount
для столбца счетчика:
df = pd.melt(df, id_vars='id', var_name='field', value_name='value')
#if constant value set this way
df['table'] = 'meds'
df['count'] = df.groupby(['id','field']).cumcount() 1
#change order of columns if necessary
df = df[['id','table','field','count','value']]
print (df)
id table field count value
0 34 meds name 1 ator
1 34 meds name 2 para
2 35 meds name 1 mar
3 34 meds name 3 mar
4 34 meds dose 1 20
5 34 meds dose 2 30
6 35 meds dose 1 20
7 34 meds dose 3 10
Редактировать:
df['count'] = df.groupby('id')['name'].cumcount() 1
df['count'] = df.groupby('id')['count'].ffill().astype(int)
df = pd.melt(df, id_vars=['id','count'], var_name='field', value_name='value')
print (df)
id count field value
0 34 1 name ator
1 34 2 name ator
2 34 3 name para
3 35 1 name mar
4 34 4 name mar
5 34 1 dose 20
6 34 2 dose 30
7 34 3 dose 30
8 35 1 dose 20
9 34 4 dose 10
Комментарии:
1. Спасибо. Это очень близко, но, к сожалению, один пациент (id) может принимать одно и то же лекарство (название) несколько раз. Ему нужно подсчитывать количество разных лекарств, а не подсчитывать идентификатор. Например, значение ator считается равным 1 для идентификатора 034, во второй раз, когда 034 принимает значение ator, оно снова должно считаться равным 1. Затем 034 принимает значение para, и оно считается как 2. Я надеюсь, что это имеет смысл 🙂