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

Есть ли более эффективный способ получить все строки, которые каким-либо образом связаны с любой другой строкой в ​​том же самом df (равенство, используемое в этом примере, фактическая функция немного сложнее):

import pandas as pd
from pydataset import data
df = data('iris')
df = df[df.index<10]
#adding ID col for ease of ref
df['ID'] = df.index
df

    Sepal.Length  Sepal.Width  Petal.Length  Petal.Width Species  ID
1           5.1          3.5           1.4          0.2  setosa   1
2           4.9          3.0           1.4          0.2  setosa   2
3           4.7          3.2           1.3          0.2  setosa   3
4           4.6          3.1           1.5          0.2  setosa   4
5           5.0          3.6           1.4          0.2  setosa   5
6           5.4          3.9           1.7          0.4  setosa   6
7           4.6          3.4           1.4          0.3  setosa   7

Все, что я могу придумать, это df.copy() и затем цикл:

df_copy = df.copy()
df_want = pd.DataFrame(columns=['ID','Sepal.Length','Sepal.Width','ExID', 'ExSepal.Length', 'ExSepal.Width'])

for row in range(0, df.shape[0]):
    for row2 in range(0, df_copy.shape[0]):
        if (df.iloc[row]['ID'] != df_copy.iloc[row2]['ID'] and
            df.iloc[row]['Sepal.Length'] == df_copy.iloc[row2]['Sepal.Length']):
                df_want = df_want.append({'ID':df.iloc[row]['ID'],
                                         'Sepal.Length':df.iloc[row]['Sepal.Length'],
                                         'Sepal.Width':df.iloc[row]['Sepal.Width'],
                                         'ExID':df_copy.iloc[row2]['ID'],
                                         'ExSepal.Length':df_copy.iloc[row2]['Sepal.Length'],
                                         'ExSepal.Width':df_copy.iloc[row2]['Sepal.Width']},
                                          ignore_index=True)
df_want

ID  Sepal.Length Sepal.Width    ExID    ExSepal.Length  ExSepal.Width
4.0  4.6             3.1        7.0          4.6          3.4
5.0  5.0             3.6        8.0          5.0          3.4
7.0  4.6             3.4        4.0          4.6          3.1
8.0  5.0             3.4        5.0          5.0          3.6

Так что row_ID 4 - это то же самое, что 7, а 5 - это то же самое, что и 8и т. д.

Попытка поиска немного, самым близким, что я нашел, было это Выбор строк из DataFrame на основе значений в столбце в пандах , но изо всех сил пытаться использовать isin() вэто дело.

Ответы [ 3 ]

0 голосов
/ 02 октября 2018

Решением может быть создание логического фильтра для дубликатов в каждом столбце и объединение его в общий фильтр.

В вашем примере объединены только первые 2 столбца, поэтому этот код делает то же самое, изменитеdf.columns[:2] для другого разделителя столбцов.

Обратите внимание, что для объединения всех фильтров нужно одинаковое имя, поэтому я переименую их.

import pandas as pd
from pydataset import data
df = data('iris')
df = df[df.index<10]
#adding ID col for ease of ref
df['ID'] = df.index

total_filter = None

for c in df.columns[:2]:
    print('checking column', c)
    filter = df[c].duplicated(keep=False).rename('dupe')
    if total_filter is None:
        total_filter = filter
    else:    
        total_filter = total_filter | filter

print(df[total_filter])

Результат

checking column Sepal.Length
checking column Sepal.Width
   Sepal.Length  Sepal.Width  Petal.Length  Petal.Width Species  ID
4           4.6          3.1           1.5          0.2  setosa   4
5           5.0          3.6           1.4          0.2  setosa   5
7           4.6          3.4           1.4          0.3  setosa   7
8           5.0          3.4           1.5          0.2  setosa   8
0 голосов
/ 02 октября 2018

Другой подход .. результаты не в том формате, как вы упомянули .. они сгруппированы

data = pd.read_csv('iris.data.txt', sep=',', header=None)
data.columns = ['Sepal.Length' , 'Sepal.Width' , 'Petal.Length',  'Petal.Width' ,'Species' , 'ID']
data['ID'] = data.index

#I guess you dont want these
data.drop(['Petal.Width','Petal.Length','Species'], axis=1, inplace=True)

def check(data):
    if len(data) > 1:
        index_list = list(data.index.values)
        index_list.append(index_list[0])
        data['ExSepal.Length'] = data['Sepal.Length']
        data['ExSepal.Width'] = data['Sepal.Width']
        data['ExId'] = [int(index_list[i]) for i in range(1,len(index_list))]
        return data

data.groupby('Sepal.Length').apply(check)

Вывод

                 Sepal.Length  Sepal.Width  ID  ExSepal.Length  ExSepal.Width  \
Sepal.Length                                                                    
4.4          8            4.4          2.9   8             4.4            2.9   
             38           4.4          3.0  38             4.4            3.0   
             42           4.4          3.2  42             4.4            3.2   
4.6          3            4.6          3.1   3             4.6            3.1   
             6            4.6          3.4   6             4.6            3.4   
             22           4.6          3.6  22             4.6            3.6   
             47           4.6          3.2  47             4.6            3.2   
4.7          2            4.7          3.2   2             4.7            3.2   
             29           4.7          3.2  29             4.7            3.2   
4.8          11           4.8          3.4  11             4.8            3.4   

                 ExId  
Sepal.Length           
4.4          8     38  
             38    42  
             42     8  
4.6          3      6  
             6     22  
             22    47  
             47     3  
4.7          2     29  
             29     2  
4.8          11    12  
0 голосов
/ 02 октября 2018

Попробуйте следующие 2 подхода.Первый, предложенный @Sarthak Negiusing с использованием group-by:

df.groupby('Sepal.Length', as_index=True).apply(lambda x: x if len(x)>1 else None)

Второй подход - просто отбрасывать неповторяющиеся значения:

ndf = df.drop(df.drop_duplicates(subset='Sepal.Length', keep=False).index)

Редактировать: добавитьExId

Это было немного сложно, и это может выглядеть не очень красиво.Подход здесь заключается в создании d1 кадра данных, который содержит дубликаты first и d2, который содержит дубликаты last, и присвоения идентификаторов d1 для d2 и наоборот ..

# keep first duplicates 
d1=ndf.drop_duplicates(subset='Sepal.Length').reset_index(drop=True)

# Keep last duplicates
d2=ndf.drop_duplicates(subset='Sepal.Length', keep='last').reset_index(drop=True)

d1['ExId'] = d2.ID
d2['ExId'] = d1.ID

# append
d1.append(d2).reset_index(drop=True)

Выход

    Sepal.Length    Sepal.Width Petal.Length    Petal.Width Species ID ExId
0   4.6             3.1         1.5             0.2         setosa  4  7
1   5.0             3.6         1.4             0.2         setosa  5  8
2   4.6             3.4         1.4             0.3         setosa  7  4
3   5.0             3.6         1.4             0.2         setosa  8  5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...