Объединить столбцы и изменить форму в строке - PullRequest
1 голос
/ 17 октября 2019

У меня есть такие данные:

data = {'Host' : ['A','A','A','A','A','A','B','B','B'], 'Duration' : ['1','2',None,'4','5',None,'7','8',None], 'Predict' : [None,None,'3',None,None,'6',None,None,'9']}
df = pd.DataFrame(data)

Это выглядит так:


Host    Duration    Predict
0   A        1       None
1   A        2       None
2   A       None       3
3   A        4       None
4   A        5       None
5   A       None       6
6   B        7       None
7   B        8       None
8   B       None       9

Что я ожидал получить:

A   1, 2, 3
A   4, 5, 6
B   7, 8, 9

Я получил то, что яхотел, но способ, который я решил, мне не нравится:

def create_vector(group):
    result = []
    df_array = []
    for index, item  in enumerate(group.Duration.ravel()):
        if (item != None):
            result.append(item)        
        else:            
            result.append(group.Predict.ravel()[index])
            result.append(-1)
    result = np.array(list(map(int, result)))
    splitted = np.split(result, np.where(result == -1)[0] + 1)
    for arr in splitted:
        if (len(arr) > 3):
            seq = ', '.join(str(e) for e in arr[:-1])
            df_array.append(seq)
    return pd.DataFrame(df_array,columns=['seq'])

Минимальная длина arr должна составлять один «Duration» плюс один «Predict»

df= df.groupby(['host']).apply(create_vector)
df= df.reset_index().rename(columns={'level_1':'Index'})
df= df.drop(columns = {'Index'})

Хотелось бы решитьэта проблема с использованием панд. Жду комментариев и советов

Ответы [ 2 ]

2 голосов
/ 17 октября 2019

Один из способов: melt, dropna для удаления недопустимых значений, затем сгруппировать и join действительные значения:

(df.melt(id_vars='Host')
   .dropna(subset=['value'])
   .groupby('Host').value
   .agg(', '.join)
   .reset_index())

    Host   value
0    A  1, 2, 3, 4, 5
1    B  6, 7, 8, 9, 0
2 голосов
/ 17 октября 2019

Я полагаю, что вы можете заменить отсутствующие значения из Duration на Predict столбец, поэтому решение упрощается:

df['new'] = df['Duration'].fillna(df['Predict']).astype(str)

Если необходимо сгруппировать каждые 3 значения по Host groups:

g = df.groupby('Host').cumcount() // 3

Или, если нужно, группировать по столбцу Predict с разделителем None - только необходимый индекс по умолчанию:

g = df.index.where(df['Predict'].notna()).to_series().bfill()

#if always unique values in Predic column
#g = df['Predict'].bfill()

df = (df.groupby(['Host', g])['new']
        .apply(', '.join)
        .reset_index(level=1, drop=True)
        .reset_index(name='Seq'))
print (df)
  Host      Seq
0    A  1, 2, 3
1    A  4, 5, 6
2    B  7, 8, 9

Другое решение с изменением формы на DataFrame.stack - None s или пропущенные значения по умолчанию удаляются снова с агрегированием join:

g = df.groupby('Host').cumcount() // 3

df = (df.set_index(['Host', g])
        .stack()
        .astype(str)
        .groupby(level=[0,1])
        .apply(', '.join)
        .reset_index(level=1, drop=True)
        .reset_index(name='Seq')
        )
print (df)
  Host      Seq
0    A  1, 2, 3
1    A  4, 5, 6
2    B  7, 8, 9
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...