Дублирование строк последовательно на основе суммы нескольких столбцов - PullRequest
0 голосов
/ 26 сентября 2018

Допустим, у меня есть следующий фрейм данных (хотя на самом деле я работаю с более чем 100 строками):

>> df 
a        b   c   d   e
title0   1   0   0   string   
title1   0   1   1   string   

Для каждой строки я хочу:

  • В col = ['b', 'c', 'd'] найдите строки, в которых имеется более одного столбца со значением = 1. Это мое условие.
  • Дублирующиеся строки, которые соответствуютВышеуказанное условие должно быть продублировано так, чтобы только первая копия = 1 для первого столбца, который = 1 в оригинале, и т. д. для n раз существует столбец со значением = 1.
  • Удалить исходную строку

Вывод должен быть:

>> df
a        b   c   d   e
title0   1   0   0   string   
title1   0   1   0   string   
title1   0   0   1   string   

Ответы [ 3 ]

0 голосов
/ 26 сентября 2018

Вы можете попытаться наложить строки там, где есть дублирование 1 относительно оси 1, затем заменить дублированные 1 на identity matrix np.identity(len(df)) в зависимости от их длины

df
        a  b  c  d        e
0  title0  1  0  0  string1
1  title1  0  1  1  string2
2  title2  1  1  1  string3
3  title3  1  1  0  string4

def fun(x):
    # Assign numpy identity matrix inplace of duplicated indexes
    x.loc[x[x.eq(1)].dropna(axis=1).index,x[x.eq(1)].dropna(axis=1).columns] = np.identity(len(x))
    return x
# Imputing rows w.r.t to the duplication of 1's count
for i,j in zip(range(len(df)),df[['b','c','d']].sum(axis=1).values):
    if i>0:
        df = df.append([df.loc[i]]*(j-1)).reset_index(drop = True)
df.groupby(['a']).apply(fun)

Out:

      a     b   c   d   e
0   title0  1.0 0.0 0.0 string1
1   title1  0.0 1.0 0.0 string2
2   title2  1.0 0.0 0.0 string3
3   title3  1.0 0.0 0.0 string4
4   title1  0.0 0.0 1.0 string2
5   title2  0.0 1.0 0.0 string3
6   title2  0.0 0.0 1.0 string3
7   title3  0.0 1.0 0.0 string4
0 голосов
/ 26 сентября 2018

Идея использования get_dummies:

print (df)
        a  b  c  d        e
0  title0  1  0  0  string1
1  title1  0  1  1  string2
2  title2  1  1  1  string3
3  title3  1  1  0  string4

#filter all columns without a and e
cols = df.columns.difference(['a','e'])
#or set columns names by list
#cols = ['b', 'c', 'd']
print (cols)
Index(['b', 'c', 'd'], dtype='object')

#filter columns and reshape to Series, filter only values by 1
s = df[cols].stack()
df1 = pd.get_dummies(s[s == 1].reset_index(level=1).drop(0, axis=1), prefix='', prefix_sep='')
print (df1)
   b  c  d
0  1  0  0
1  0  1  0
1  0  0  1
2  1  0  0
2  0  1  0
2  0  0  1
3  1  0  0
3  0  1  0

#last remove original columns, join new df and for same order use reindex
df = df.drop(cols, axis=1).join(df1).reindex(columns=df.columns).reset_index(drop=True)
print (df)
        a  b  c  d        e
0  title0  1  0  0  string1
1  title1  0  1  0  string2
2  title1  0  0  1  string2
3  title2  1  0  0  string3
4  title2  0  1  0  string3
5  title2  0  0  1  string3
6  title3  1  0  0  string4
7  title3  0  1  0  string4
0 голосов
/ 26 сентября 2018
# if you have this df named a , then you could try this code.
import numpy as np
import pandas as pd
a = pd.DataFrame(columns=["b","c","d","e"])
a.loc["title0",:] = [1,0,0,"string"]
a.loc["title1",:] = [0,1,1,"string"]
a.index.name = "a"
col_names = ['b','c','d']
for idx in a.index:
    current_line = a.loc[idx,:]
    process_part = current_line[col_names]
    if sum(process_part)>1:
        a = a.drop(idx)
        for col,v in zip(col_names,process_part):
            if v == 1:
                keep_one = np.zeros(3)
                keep_one[col_names.index(col)] = 1
                a = a.append(pd.DataFrame.from_dict({idx:dict(zip(a.columns,list(keep_one)+[current_line[-1]]))},orient="index"))
...