我有一个数据集,如下所示:
A B
1 aa 1234
2 ab 3456
3 bc [1357, 2468]
4 cc 8901
...
我需要迭代B列并将方括号([])中的所有值替换为这些括号中的四个左数字,因此数据集将如下所示:
A B
1 aa 1234
2 ab 3456
3 bc 1357
4 cc 8901
...
我有这段代码:
for item in df['B']:
if len(item) > 4:
item_v = str(item[1:5])
df['B'][item] = item_v
print(df['B'][item])
打印截断值,但是,如果我检查df的头部,它仍然具有旧值:
> df['B'].head()
> A B
1 aa 1234
2 ab 3456
3 bc [1357, 2468]
4 cc 8901
...
我做错了什么?
答案 0 :(得分:2)
在您的代码中,您循环遍历数据框B列中的项目,但您无法将索引重新编入原始数据框。具体来说,行:
df['B'][item] = item_v
,
没有做你想做的事。它在B列中放置一个新项目,索引为item
。如果您使用较小的数据帧进行尝试,您可能会在帧的末尾看到一些奇数值。当我尝试这个时,我得到:
In[36]: df
Out[36]:
A B
0 aa 1234
1 ab 3456
2 bc 1357
3 cc 8901
In[37]: df['B'][item] = item_v
In[38]: df['B']
Out[38]:
0 1234
1 3456
2 1357
3 8901
8901 8901 <-- ???
Name: B, dtype: object
更糟糕的是,此行不会将值插入到您期望的数据框中。当您查看df['B']
时,您只会看到新元素。如果仅查看df
,您将看到没有额外项目的原始数据框。
正确的方法是在数据框中设置元素是使用.loc[]
,如:
df.loc[item,'B'] = item_v
这仍然没有解决原始问题,即如何获得正确的索引。原始代码的一个修复是为列表中的B列中的每个项目累积值,然后将其分配回B列,如下所示:
newB = []
for item in df['B']:
if len(item) > 4:
item_v = str(item[1:5])
else:
item_v = item
newB.append(item_v)
print(newB)
df.loc[:, 'B'] = newB
但是,对于pandas
,还有一些解决方案不需要直接迭代B列中的项目。
例如,您可以使用.where()
仅替换长度超过4个字符的字符串以及.str
函数来操作文本元素。这一个班轮将完成这项工作:
df.loc[:,'B'] = df['B'].where((df['B'].str.len() <= 4), df['B'].str[1:5])
如果字符为4个或更少字符,则此语句创建一个包含B列中项目的系列,如果长度超过4个字符,则创建包含B列中项目的切片[1:5]。然后指定此系列替换df
中的B列。
答案 1 :(得分:1)
最简单快捷的方法是使用Pandas str.get()功能并为所需结果创建另一列。
解决方案#1
如果B
中的值为整数[1234,3456,[1357, 2468],8901]
df['C'] = df['B'].str.get(0).astype(float)
df.C.fillna(df['B'], inplace=True)
df['C'] = df.C.astype(int, inplace=True)
输出:
A B C
0 aa 1234 1234
1 ab 3456 3456
2 bc [1357, 2468] 1357
3 cc 8901 8901
然后,如果您不需要,可以删除B列。
解决方案#2
如果B
中的值为字符串['1234','3456',['1357', '2468'],'8901']
import re
df['digits'] = df['B'].apply(lambda x: re.findall('\d+', str(x)))
df['digits'] = df['digits'].str.get(0)
print(df)
输出:
A B digits
0 aa 1234 1234
1 ab 3456 3456
2 bc [1357, 2468] 1357
3 cc 8901 8901
同样,如果您不需要,可以删除B列。