Разделите строки для создания новых строк в фрейме данных Pandas с теми же значениями других строк

#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()) данные . Убедитесь, что между таблицей и предыдущим текстом есть пустая строка, иначе она не будет проанализирована.