web-dev-qa-db-ja.com

別の値に変更されるまで値の出現をカウントする

次のDataFrameがあります。

df = pd.DataFrame([10, 10, 23, 23, 9, 9, 9, 10, 10, 10, 10, 12], columns=['values'])

各値の頻度を計算しますが、全体のカウントは計算しません。別の値に変更されるまでの各値のカウントです。

私は試した:

df['values'].value_counts()

しかし、それは私に与えます

10    6
9     3
23    2
12    1

望ましい出力は

10:2 
23:2
 9:3
10:4
12:1

これどうやってするの?

9
Sascha

使用する:

df = df.groupby(df['values'].ne(df['values'].shift()).cumsum())['values'].value_counts()

または:

df = df.groupby([df['values'].ne(df['values'].shift()).cumsum(), 'values']).size()

print (df)
values  values
1       10        2
2       23        2
3       9         3
4       10        4
5       12        1
Name: values, dtype: int64

最初のレベルを削除するための最後:

df = df.reset_index(level=0, drop=True)
print (df)
values
10    2
23    2
9     3
10    4
12    1
dtype: int64

説明

元の列を shift 等しくない ne で比較してから、追加 cumsum ヘルパー用Series

print (pd.concat([df['values'], a, b, c], 
                 keys=('orig','shifted', 'not_equal', 'cumsum'), axis=1))
    orig  shifted  not_equal  cumsum
0     10      NaN       True       1
1     10     10.0      False       1
2     23     10.0       True       2
3     23     23.0      False       2
4      9     23.0       True       3
5      9      9.0      False       3
6      9      9.0      False       3
7     10      9.0       True       4
8     10     10.0      False       4
9     10     10.0      False       4
10    10     10.0      False       4
11    12     10.0       True       5
13
jezrael

df['values']の変更が発生した場所を追跡できます。

changes = df['values'].diff().ne(0).cumsum()
print(changes)

0     1
1     1
2     2
3     2
4     3
5     3
6     3
7     4
8     4
9     4
10    4
11    5

そして groupby 変更とdf['values'](それらをインデックスとして保持するため)各グループの size を計算します

df.groupby([changes,'values']).size().reset_index(level=0, drop=True)

values
10    2
23    2
9     3
10    4
12    1
dtype: int64
6
yatu

itertools.groupby

from itertools import groupby

pd.Series(*Zip(*[[len([*v]), k] for k, v in groupby(df['values'])]))

10    2
23    2
9     3
10    4
12    1
dtype: int64

それは発電機です

def f(x):
  count = 1
  for this, that in Zip(x, x[1:]):
    if this == that:
      count += 1
    else:
      yield count, this
      count = 1
  yield count, [*x][-1]

pd.Series(*Zip(*f(df['values'])))

10    2
23    2
9     3
10    4
12    1
dtype: int64
5
piRSquared

crosstabの使用

df['key']=df['values'].diff().ne(0).cumsum()
pd.crosstab(df['key'],df['values'])
Out[353]: 
values  9   10  12  23
key                   
1        0   2   0   0
2        0   0   0   2
3        3   0   0   0
4        0   4   0   0
5        0   0   1   0

上記の結果を少し変更します

pd.crosstab(df['key'],df['values']).stack().loc[lambda x:x.ne(0)]
Out[355]: 
key  values
1    10        2
2    23        2
3    9         3
4    10        4
5    12        1
dtype: int64

pythongroupbyに基づく

from itertools import groupby

[ (k,len(list(g))) for k,g in groupby(df['values'].tolist())]
Out[366]: [(10, 2), (23, 2), (9, 3), (10, 4), (12, 1)]
4
WeNYoBen

これは、このスレッドで最も時間/メモリ効率の良い方法とはほど遠いですが、ここでは、非常に簡単な反復アプローチを示します。この方法の改善を提案することをお勧めします。

import pandas as pd

df = pd.DataFrame([10, 10, 23, 23, 9, 9, 9, 10, 10, 10, 10, 12], columns=['values'])

dict_count = {}
for v in df['values'].unique():
    dict_count[v] = 0

curr_val = df.iloc[0]['values']
count = 1
for i in range(1, len(df)):
    if df.iloc[i]['values'] == curr_val:
        count += 1
    else:
        if count > dict_count[curr_val]:
            dict_count[curr_val] = count
        curr_val = df.iloc[i]['values']
        count = 1
if count > dict_count[curr_val]:
    dict_count[curr_val] = count

df_count = pd.DataFrame(dict_count, index=[0])
print(df_count)
0
UBears

groupbyでは、itertoolsの関数strが役立ちます。

>>> string = 'aabbaacc'
>>> for char, freq in groupby('aabbaacc'):
>>>     print(char, len(list(freq)), sep=':', end='\n')
[out]:
    a:2
    b:2
    a:2
    c:2

この関数はlistでも機能します。

>>> df = pd.DataFrame([10, 10, 23, 23, 9, 9, 9, 10, 10, 10, 10, 12], columns=['values'])
>>> for char, freq in groupby(df['values'].tolist()):
>>>     print(char, len(list(freq)), sep=':', end='\n')
[out]:
    10:2
    23:2
     9:3
    10:4
    12:1

Notedfの場合、DataFrameには属性valuesがあるため、df ['values']のように常にこの方法を使用して 'values'列を取得します。

0
TimeSeam