#python #pandas #split #explode
Вопрос:
У меня есть фрейм данных pandas, в котором один столбец текстовых строк содержит несколько значений, разделенных запятыми. Я хочу разделить каждое поле и создать новую строку для каждой записи только там, где количество запятых >= 2. Например, a должно стать b:
In [7]: a
Out[7]:
var1 var2 var3
0 a,b,c,d 1 X1
1 a,b,c,d 1 X2
2 a,b,c,d 1 X3
3 a,b,c,d 1
4 e,f,g 2 Y1
5 e,f,g 2 Y2
6 e,f,g 2
7 h,i 3 Z1
In [8]: b
Out[8]:
var1 var2 var3
0 a,d 1 X1
1 b,d 1 X2
3 c,d 1 X3
4 e,g 2 Y1
5 f,g 2 Y2
6 h,i 3 Z1
Комментарии:
1. я не понял,как вы выбираете в a,b,c, d, какая из пары будет var, это может быть ab, ac, ad, bd, bc, bd, cd..
2. @Tomer S он должен быть сопряжен с последним элементом. Каждый из первых 1,2,3…. n-1 элементов должен быть сопряжен с n-м элементом.
Ответ №1:
Вы можете использовать пользовательскую функцию:
def custom_split(r):
if r['var3']:
s = r['var1']
i = int(r['var3'][1:])-1
l = s.split(',')
return l[i] ',' l[-1]
df['var1'] = df.apply(custom_split, axis=1)
df = df.dropna()
выход:
var1 var2 var3
0 a,d 1 X1
1 b,d 1 X2
2 c,d 1 X3
4 e,g 2 Y1
5 f,g 2 Y2
7 h,i 3 Z1
Ответ №2:
df['cc'] = df.groupby('var1')['var1'].cumcount()
df['var1'] = df['var1'].str.split(',')
df['var1'] = df[['cc','var1']].apply(lambda x: x['var1'][x['cc']] ',' x['var1'][-1],axis=1)
df = df.dropna().drop(columns=['cc']).reset_index(drop=True)
df
Комментарии:
1. Как получилось, что все три ответа были отклонены ???
2. Должно быть, у кого-то плохое настроение, я дал тебе голос, чтобы загладить свою вину
3. ОК. Я возвращаю тебе один. 😉
Ответ №3:
Вы можете сделать это, разделив var1
запятую на списки. Целое число в var3
минус 1 можно интерпретировать как индекс того, какой элемент в списке var1
необходимо сохранить:
import pandas as pd
import io
data = ''' var1 var2 var3
0 a,b,c,d 1 X1
1 a,b,c,d 1 X2
2 a,b,c,d 1 X3
3 a,b,c,d 1
4 e,f,g 2 Y1
5 e,f,g 2 Y2
6 e,f,g 2
7 h,i 3 Z1'''
df = pd.read_csv(io.StringIO(data), sep = r'ss ', engine='python')
df['var1'] = df["var1"].str.split(',').apply(lambda x: [[i,x[-1]] for i in x[:-1]]) #split the string to list and create combinations of all items with the last item in the list
df = df[df['var3'].notnull()] # drop rows where var3 is None
df['var1'] = df.apply(lambda x: x['var1'][0 if not x['var3'] else int(x['var3'][1:])-1], axis=1) #keep only the element in the list in var1 where the index is the integer in var3 minus 1
Выход:
var1 | var2 | var3 | |
---|---|---|---|
0 | [«а», «д»] | 1 | X1 |
1 | [‘b’, ‘d’] | 1 | X2 |
2 | [‘c’, ‘d’] | 1 | X3 |
4 | [‘e’, ‘g’] | 2 | Y1 |
5 | [‘f’, ‘g’] | 2 | Y2 |
7 | [«х», «я»] | 3 | Z1 |
Запустите df['var1'] = df['var1'].str.join(',')
для var1
повторного преобразования в строку.
Комментарии:
1. Мне нравится, как вы играете с индексом внутри приложения, в то время как я использую cumcount. Я думаю, что вы отбрасываете последний (дополнительный) элемент, отбрасывая нуль в var3, тогда как я отбрасываю на основе nan (что опасно, если в ячейках есть nan). кстати, какой IDE вы используете ? Он генерирует таблицу, похожую на excel.
2. @EBDS stackoverflow может анализировать таблицы уценки. Просто скопируйте и вставьте выходные
print(df.to_markdown())
данные . Убедитесь, что между таблицей и предыдущим текстом есть пустая строка, иначе она не будет проанализирована.