Выбор строки на основе варианта столбца - PullRequest
0 голосов
/ 24 мая 2018

Предположим, у нас есть файл с именем any_csv.csv, содержащий ...

A,B,random
1,2,300
3,4,300
5,6,300
1,2,300
3,4,350
8,9,350
4,5,350
5,6,320
7,8,300
3,3,300

Я хочу сохранить все строки, где random изменяется / изменяется.Я сделал эту небольшую программу для достижения этой цели, но, поскольку я хочу больше узнать о пандах и поскольку моя программа работает медленнее, чем я ожидаю (~ 130 секунд, чтобы обработать файл журнала объемом 1,2 миллиона строк), я прошу вашей помощи.

import pandas as pd
import numpy as np

df = pd.read_csv('any_csv.csv')
mask = np.zeros(len(df.index), dtype=bool)

#   Initializing my current value for comparison purposes.
mask[0] = 1
previous_val = df.iloc[0]['random']
for index, row in df.iterrows():
    if row['random'] != previous_val:
        #   If a variation has been detected, switch to True current, and previous index.
        previous_val = row['random']
        mask[index] = 1
        mask[index - 1] = 1

#   Keeping the last item.
mask[-1] = 1

df = df.loc[mask]
df.to_csv('any_other_csv.csv', index=False)

Полагаю, вкратце, я хотел бы знать, как применить мой if в этом самодельном цикле for, который в целом довольно медленный.

Результаты:

A,B,random
1,2,300
1,2,300
3,4,350
4,5,350
5,6,320
7,8,300
3,3,300

Ответы [ 3 ]

0 голосов
/ 24 мая 2018

Используйте boolean indexing с 2 масками для проверки различных значений с shift и ne для не равных:

df = df[df['random'].ne(df['random'].shift()) | df['random'].ne(df['random'].shift(-1))]
print (df)
   A  B  random
0  1  2     300
3  1  2     300
4  3  4     350
6  4  5     350
7  5  6     320
8  7  8     300
9  3  3     300

Для лучшей проверки:

df['mask1'] = df['random'].ne(df['random'].shift()) 
df['mask2'] = df['random'].ne(df['random'].shift(-1))
df['mask3'] = df['random'].ne(df['random'].shift()) | df['random'].ne(df['random'].shift(-1))
print (df)
   A  B  random  mask1  mask2  mask3
0  1  2     300   True  False   True
1  3  4     300  False  False  False
2  5  6     300  False  False  False
3  1  2     300  False   True   True
4  3  4     350   True  False   True
5  8  9     350  False  False  False
6  4  5     350  False   True   True
7  5  6     320   True   True   True
8  7  8     300   True  False   True
9  3  3     300  False   True   True

Сроки :

N = 1000

In [157]: %timeit orig(df)
56.8 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [158]: %timeit (df[df['random'].ne(df['random'].shift()) | 
df['random'].ne(df['random'].shift(-1))])
939 µs ± 7.61 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

#jpp solution - a bit slowier
In [159]: %timeit df[(df['random'] != df['random'].shift()) | (df['random'] != df['random'].shift(-1))]
1.11 ms ± 8.71 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
N = 10000

In [160]: %timeit orig(df)
538 ms ± 3.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [161]: %timeit (df[df['random'].ne(df['random'].shift()) | df['random'].ne(df['random'].shift(-1))])
1.16 ms ± 75 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

#jpp solution - a bit slowier
In [162]: %timeit df[(df['random'] != df['random'].shift()) | (df['random'] != df['random'].shift(-1))]
1.28 ms ± 8.51 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

np.random.seed(123)
N = 1000
df = pd.DataFrame({'random':np.random.randint(2, size=N)})
print (df)


def orig(df):
    mask = np.zeros(len(df.index), dtype=bool)

#   Initializing my current value for comparison purposes.
    mask[0] = 1
    previous_val = df.iloc[0]['random']
    for index, row in df.iterrows():
        if row['random'] != previous_val:
            #   If a variation has been detected, switch to True current, and previous index.
            previous_val = row['random']
            mask[index] = 1
            mask[index - 1] = 1

    #   Keeping the last item.
    mask[-1] = 1

    return df.loc[mask]
0 голосов
/ 24 мая 2018

Вы можете попробовать что-то вроде ниже: `

df.groupby(["A", "Random"]).filter(lambda df:df.shape[0] == 1)
0 голосов
/ 24 мая 2018

Вы можете использовать pd.Series.shift для создания маски логических значений.Булева маска указывает, когда значение отличается от значения выше или ниже его в серии.

Затем можно применить булеву маску непосредственно к вашему фрейму данных.

mask = (df['random'] != df['random'].shift()) | \
       (df['random'] != df['random'].shift(-1))

df = df[mask]

print(df)

   A  B  random
0  1  2     300
3  1  2     300
4  3  4     350
6  4  5     350
7  5  6     320
8  7  8     300
9  3  3     300
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...