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

у меня есть ниже датафрейм, который имеет столбцы 0-1 .. и я хочу посчитать число 0-> 1,1-> 0 в каждом столбце. в нижнем фрейме данных номер изменения состояния столбца «6», номер изменения состояния «b» равен 3 , 'c' номер изменения состояния равен 2 .. на самом деле я не знаю, как код в пандах.

number a b c
1      0 0 0
2      1 0 1
3      0 1 1
4      1 1 1
5      0 0 0
6      1 0 0
7      0 1 0

на самом деле я не имею представления о пандах .. потому что недавно использовал только r. но теперь я должен использовать питона панд. так что немного сложнее ситуация кто-нибудь может помочь? заранее спасибо !

Ответы [ 6 ]

0 голосов
/ 07 ноября 2018

Немного xor (^)

Используйте массив Numpy df.values и сравните смещенные элементы с ^
Это должно быть быстрое решение.

Xor обладает свойством, что только один из двух оперируемых предметов может быть истинным, как показано в этой таблице истинности

A B XOR
T T   F
T F   T
F T   T
F F   F

И тиражируется в 0 / 1 форме

a = np.array([1, 1, 0, 0])
b = np.array([1, 0, 1, 0])

pd.DataFrame(dict(A=a, B=b, XOR=a ^ b))

   A  B  XOR
0  1  1    0
1  1  0    1
2  0  1    1
3  0  0    0

Демо

v = df.values

pd.Series((v[1:] ^ v[:-1]).sum(0), df.columns)

a    6
b    3
c    2
dtype: int64

Время тестирования

Открыть в Colab
Открыть в GitHub

Функции

def pir_xor(df):
  v = df.values
  return pd.Series((v[1:] ^ v[:-1]).sum(0), df.columns)

def pir_diff1(df):
  v = df.values
  return pd.Series(np.abs(np.diff(v, axis=0)).sum(0), df.columns)

def pir_diff2(df):
  v = df.values
  return pd.Series(np.diff(v.astype(np.bool), axis=0).sum(0), df.columns)

def cold(df):
  return df.ne(df.shift(-1)).sum(0) - 1

def jez(df):
  return df.rolling(2).apply(lambda x: x[0] != x[-1]).sum().astype(int)

def naga(df):
  return df.diff().abs().sum().astype(int)

Тестирование

np.random.seed([3, 1415])

idx = [10, 30, 100, 300, 1000, 3000, 10000, 30000, 100000, 300000]
col = 'pir_xor pir_diff1 pir_diff2 cold jez naga'.split()
res = pd.DataFrame(np.nan, idx, col)

for i in idx:
  df = pd.DataFrame(np.random.choice([0, 1], size=(i, 3)), columns=[*'abc'])
  for j in col:
    stmt = f"{j}(df)"
    setp = f"from __main__ import {j}, df"
    res.at[i, j] = timeit(stmt, setp, number=100)

Результаты

res.div(res.min(1), 0)

        pir_xor  pir_diff1  pir_diff2       cold         jez      naga
10      1.06203   1.119769   1.000000  21.217555   16.768532  6.601518
30      1.00000   1.075406   1.115743  23.229013   18.844025  7.212369
100     1.00000   1.134082   1.174973  22.673289   21.478068  7.519898
300     1.00000   1.119153   1.166782  21.725495   26.293712  7.215490
1000    1.00000   1.106267   1.167786  18.394462   37.925160  6.284253
3000    1.00000   1.118554   1.342192  16.053097   64.953310  5.594610
10000   1.00000   1.163557   1.511631  12.008129  106.466636  4.503359
30000   1.00000   1.249835   1.431120   7.826387  118.380227  3.621455
100000  1.00000   1.275272   1.528840   6.690012  131.912349  3.150155
300000  1.00000   1.279373   1.528238   6.301007  140.667427  3.190868

res.plot(loglog=True, figsize=(15, 8))

enter image description here

0 голосов
/ 07 ноября 2018

shift и сравнение:

df.ne(df.shift(-1)).sum(0) - 1

a    6
b    3
c    2
dtype: int64

... Предполагая, что "число" является индексом, в противном случае перед вашим решением введите
df.set_index('number', inplace=True).

0 голосов
/ 07 ноября 2018

Вы можете попробовать также:

((df!=df.shift()).cumsum() - 1).iloc[-1:]
0 голосов
/ 07 ноября 2018

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

def agg_columns(x):
    shifted = x.shift()
    return sum(x[1:] != shifted[1:])

df[['a','b','c']].apply(agg_columns)

a    6
b    3
c    2
dtype: int64
0 голосов
/ 07 ноября 2018

Вы можете попытаться взять разницу с предыдущим и добавить абсолютные значения

df.diff().abs().sum().astype(int)

Из:

1    6
2    3
3    2
dtype: int32
0 голосов
/ 07 ноября 2018

Используйте rolling и сравните каждое значение, затем посчитайте все значения True на sum:

df = df[['a','b','c']].rolling(2).apply(lambda x: x[0] != x[-1], raw=True).sum().astype(int)
a    6
b    3
c    2
dtype: int64
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...