我在pandas
数据框中有许多基于字符串的列,我希望在scikitlearn
分类模型上使用这些列。我知道我必须使用oneHotEncoder
来正确编码变量,但首先,我想减少列中的变化,取出列中出现的时间少于x%的字符串,或者不在列中的count前面的x个字符串中。
以下是一个例子:
df1 = pd.DataFrame({'a':range(22), 'b':list('aaaaaaaabbbbbbbcccdefg'), 'c':range(22)})
df1
a b c
0 0 a 0
1 1 a 1
2 2 a 2
3 3 a 3
4 4 a 4
5 5 a 5
6 6 a 6
7 7 a 7
8 8 b 8
9 9 b 9
10 10 b 10
11 11 b 11
12 12 b 12
13 13 b 13
14 14 b 14
15 15 c 15
16 16 c 16
17 17 c 17
18 18 d 18
19 19 e 19
20 20 f 20
21 21 g 21
如您所见,a,b和c出现在b列的时间超过10%,所以我想保留它们。另一方面,d,e,f和g看起来不到10%(实际上约占5%的时间),所以我想通过将它们变成'其他'来解决这些问题:
df1['b']
0 a
1 a
2 a
3 a
4 a
5 a
6 a
7 a
8 b
9 b
10 b
11 b
12 b
13 b
14 b
15 c
16 c
17 c
18 other
19 other
20 other
21 other
我同样希望能够说我只想保留频率方面出现在前2位的值,因此b列看起来像这样:
df1['b']
0 a
1 a
2 a
3 a
4 a
5 a
6 a
7 a
8 b
9 b
10 b
11 b
12 b
13 b
14 b
15 other
16 other
17 other
18 other
19 other
20 other
21 other
我没有在熊猫身上看到一个明显的方法来做到这一点,尽管我确实在R中对此有了更多的了解。任何想法?关于如何使Nones更加健壮的任何想法,可能会出现超过10%的时间或者位于前x个值中?
答案 0 :(得分:4)
这有点扭曲,但这是一个复杂的问题。
首先,得到计数:
In [24]: sizes = df1["b"].value_counts()
In [25]: sizes
Out[25]:
b
a 8
b 7
c 3
d 1
e 1
f 1
g 1
dtype: int64
现在,选择你不喜欢的指数:
In [27]: bad = sizes.index[sizes < df1.shape[0]*0.1]
In [28]: bad
Out[28]: Index([u'd', u'e', u'f', u'g'], dtype='object')
最后,分配&#34;其他&#34;到那些包含坏索引的行:
In [34]: df1.loc[df1["b"].isin(bad), "b"] = "other"
In [36]: df1
Out[36]:
a b c
0 0 a 0
1 1 a 1
2 2 a 2
3 3 a 3
4 4 a 4
5 5 a 5
6 6 a 6
7 7 a 7
8 8 b 8
9 9 b 9
10 10 b 10
11 11 b 11
12 12 b 12
13 13 b 13
14 14 b 14
15 15 c 15
16 16 c 16
17 17 c 17
18 18 other 18
19 19 other 19
20 20 other 20
21 21 other 21
[22 rows x 3 columns]
您可以使用sizes.sort()
并从结果中获取最后n
个值,以便找到前两个索引。
修改:你应该可以做这样的事情,替换&#34; b&#34;的所有实例。与filterByColumn
:
def filterDataFrame(df1, filterByColumn):
sizes = df1[filterByColumn].value_counts()
...
答案 1 :(得分:1)
这是我的解决方案:
def cleanupData(inputCol, fillString, cutoffPercent=None, cutoffNum=31):
col=inputCol
col.fillna(fillString, inplace=True)
valueCounts=col.value_counts()
totalAmount=sum(valueCounts)
if cutoffPercent is not None and cutoffNum is not None:
raise NameError("both cutoff percent and number have values. Please only give one of these values")
if cutoffPercent is not None:
cutoffAmount=cutoffPercent*totalAmount
valuesToKeep=valueCounts[valueCounts>cutoffAmount]
valuesToKeep=valuesToKeep.index.tolist()
numValuesKept=len(valuesToKeep)
print "keeping "+str(numValuesKept)+" unique values in the returned column"
if cutoffNum is not None:
valueNames=valueCounts.index.tolist()
valuesToKeep=valueNames[0:cutoffNum]
newlist=[]
for row in col:
if any(row in element for element in valuesToKeep):
newlist.append(row)
else:
newlist.append("Other")
return newlist
##
cleanupData(df1['b'], "Other", cutoffNum=2)
['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'Other', 'Other', 'Other', 'Other', 'Other', 'Other', 'Other']
答案 2 :(得分:0)
将您的帧分配给变量(我称之为x),然后在“b”列
中计算每个值d = {s: sum(x["b"].values==s) for s in set(x["b"].values)}
如果d [s]低于某个阈值,则可以使用此掩码分配新值
x[x["b"].values==s] = "Call me Peter Maffay"