Pandas 非数字数据的滚动多数
给定一个数据帧:Pandas 非数字数据的滚动多数,pandas,categorical-data,Pandas,Categorical Data,给定一个数据帧: df = pd.DataFrame({'a' : [1,1,1,1,1,2,1,2,2,2,2]}) 我想用“a”周围的大多数值替换“a”列中的每个值。对于数值数据,我可以这样做: def majority(window): freqs = scipy.stats.itemfreq(window) max_votes = freqs[:,1].argmax() return freqs[max_votes,0] df['a'] = pd.rollin
df = pd.DataFrame({'a' : [1,1,1,1,1,2,1,2,2,2,2]})
我想用“a”周围的大多数值替换“a”列中的每个值。对于数值数据,我可以这样做:
def majority(window):
freqs = scipy.stats.itemfreq(window)
max_votes = freqs[:,1].argmax()
return freqs[max_votes,0]
df['a'] = pd.rolling_apply(df['a'], 3, majority)
我得到:
In [43]: df
Out[43]:
a
0 NaN
1 NaN
2 1
3 1
4 1
5 1
6 1
7 2
8 2
9 2
10 2
我将不得不处理南斯,但除此之外,这或多或少是我想要的。。。除了,我想对非数字列做同样的事情,但熊猫似乎不支持这一点:
In [47]: df['b'] = list('aaaababbbba')
In [49]: df['b'] = pd.rolling_apply(df['b'], 3, majority)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-49-507f45aab92c> in <module>()
----> 1 df['b'] = pd.rolling_apply(df['b'], 3, majority)
/usr/local/lib/python2.7/dist-packages/pandas/stats/moments.pyc in rolling_apply(arg, window, func, min_periods, freq, center, args, kwargs)
751 return algos.roll_generic(arg, window, minp, offset, func, args, kwargs)
752 return _rolling_moment(arg, window, call_cython, min_periods, freq=freq,
--> 753 center=False, args=args, kwargs=kwargs)
754
755
/usr/local/lib/python2.7/dist-packages/pandas/stats/moments.pyc in _rolling_moment(arg, window, func, minp, axis, freq, center, how, args, kwargs, **kwds)
382 arg = _conv_timerule(arg, freq, how)
383
--> 384 return_hook, values = _process_data_structure(arg)
385
386 if values.size == 0:
/usr/local/lib/python2.7/dist-packages/pandas/stats/moments.pyc in _process_data_structure(arg, kill_inf)
433
434 if not issubclass(values.dtype.type, float):
--> 435 values = values.astype(float)
436
437 if kill_inf:
ValueError: could not convert string to float: a
我曾尝试将a转换为范畴,但即使如此,我也会遇到同样的错误。我可以先转换成分类,处理代码,最后再从代码转换回标签,但这看起来真的很复杂
有更简单/更自然的解决方案吗
顺便说一句:我仅限于NumPy 1.8.2,所以我必须使用itemfreq而不是unique,请参见。这里有一种方法,可以通过定义自己的滚动应用函数来实现
import pandas as pd
df = pd.DataFrame({'a' : [1,1,1,1,1,2,1,2,2,2,2]})
df['b'] = np.where(df.a == 1, 'A', 'B')
print(df)
Out[60]:
a b
0 1 A
1 1 A
2 1 A
3 1 A
4 1 A
5 2 B
6 1 A
7 2 B
8 2 B
9 2 B
10 2 B
def get_mode_from_Series(series):
return series.value_counts().index[0]
def my_rolling_apply_char(frame, window, func):
index = frame.index[window-1:]
values = [func(frame.iloc[i:i+window]) for i in range(len(frame)-window+1)]
return pd.Series(data=values, index=index).reindex(frame.index)
my_rolling_apply_char(df.b, 3, get_mode_from_Series)
Out[61]:
0 NaN
1 NaN
2 A
3 A
4 A
5 A
6 A
7 B
8 B
9 B
10 B
dtype: object
这里是一种通过定义自己的滚动应用函数来实现的方法
import pandas as pd
df = pd.DataFrame({'a' : [1,1,1,1,1,2,1,2,2,2,2]})
df['b'] = np.where(df.a == 1, 'A', 'B')
print(df)
Out[60]:
a b
0 1 A
1 1 A
2 1 A
3 1 A
4 1 A
5 2 B
6 1 A
7 2 B
8 2 B
9 2 B
10 2 B
def get_mode_from_Series(series):
return series.value_counts().index[0]
def my_rolling_apply_char(frame, window, func):
index = frame.index[window-1:]
values = [func(frame.iloc[i:i+window]) for i in range(len(frame)-window+1)]
return pd.Series(data=values, index=index).reindex(frame.index)
my_rolling_apply_char(df.b, 3, get_mode_from_Series)
Out[61]:
0 NaN
1 NaN
2 A
3 A
4 A
5 A
6 A
7 B
8 B
9 B
10 B
dtype: object
下面是一种使用pd.Category的方法:
import scipy.stats as stats
import pandas as pd
def majority(window):
freqs = stats.itemfreq(window)
max_votes = freqs[:,1].argmax()
return freqs[max_votes,0]
df = pd.DataFrame({'a' : [1,1,1,1,1,2,1,2,2,2,2]})
df['a'] = pd.rolling_apply(df['a'], 3, majority)
df['b'] = list('aaaababbbba')
cat = pd.Categorical(df['b'])
df['b'] = pd.rolling_apply(cat.codes, 3, majority)
df['b'] = df['b'].map(pd.Series(cat.categories))
print(df)
屈服
a b
0 NaN NaN
1 NaN NaN
2 1 a
3 1 a
4 1 a
5 1 a
6 1 b
7 2 b
8 2 b
9 2 b
10 2 b
下面是一种使用pd.Category的方法:
import scipy.stats as stats
import pandas as pd
def majority(window):
freqs = stats.itemfreq(window)
max_votes = freqs[:,1].argmax()
return freqs[max_votes,0]
df = pd.DataFrame({'a' : [1,1,1,1,1,2,1,2,2,2,2]})
df['a'] = pd.rolling_apply(df['a'], 3, majority)
df['b'] = list('aaaababbbba')
cat = pd.Categorical(df['b'])
df['b'] = pd.rolling_apply(cat.codes, 3, majority)
df['b'] = df['b'].map(pd.Series(cat.categories))
print(df)
屈服
a b
0 NaN NaN
1 NaN NaN
2 1 a
3 1 a
4 1 a
5 1 a
6 1 b
7 2 b
8 2 b
9 2 b
10 2 b
毕竟,我认为通过分类是最简单的方法,但我接受这一点,因为我明确要求一些不同的东西。顺便说一句:我对熊猫的整个索引业务不太清楚:你能解释一下index=index和reindex位的作用吗?@JohannesBauer index=index强制返回的pd.Series具有索引2,3,…,10,而不是默认的整数索引0,1,…,8。最后一个重新索引部分尝试将索引与原始df对齐,并用NaN填充看不见的索引。非常感谢,@Jianxun。这是上帝的恩赐。仍然不知道我的滚动应用字符做什么,但它使滚动应用在字符串上工作,这就是我所关心的!毕竟,我认为通过分类是最简单的方法,但我接受这一点,因为我明确要求一些不同的东西。顺便说一句:我对熊猫的整个索引业务不太清楚:你能解释一下index=index和reindex位的作用吗?@JohannesBauer index=index强制返回的pd.Series具有索引2,3,…,10,而不是默认的整数索引0,1,…,8。最后一个重新索引部分尝试将索引与原始df对齐,并用NaN填充看不见的索引。非常感谢,@Jianxun。这是上帝的恩赐。仍然不知道我的滚动应用字符做什么,但它使滚动应用在字符串上工作,这就是我所关心的!这是一个很好的解决方法,使用类别代码和类别将其转换为数字并返回+1这是一个很好的解决方法,使用类别代码和类别转换为数字并返回+1.