使用另一列的子字符串创建字典键

时间:2018-04-18 21:19:59

标签: python pandas dictionary

我有一个数据框,其中包含纽约市(曼哈顿,布鲁克林等)的行政区名称。我想创建另一个列'borough_num',为每个行政区划分一个号码(曼哈顿 - > 1,布鲁克林 - > 2,皇后区 - > 3,史坦顿岛 - > 4,布朗克斯 - > 5,其他 - > 0)。

然而,在Borough专栏中,有些行在行政区名称前面包含数字(例如,而不是“Bronx”,我有“07 Bronx”)。因为这个“07布朗克斯”仍然是布朗克斯区的一部分,所以它也应该被指定为与“布朗克斯”相同的值“5”。因此,我需要创建一个字典,将数字5分配给包含单词“Bronx”的字符串。每个自治市都一样。有关如何做到这一点的任何线索?我是python的新手!

这是我在注意到具有数字的单元格之前所拥有的:

df['Borough'] = df['Borough'].fillna('OTHER')
borough_dict = {'MANHATTAN':1, 'BROOKLYN':2, 'QUEENS': 3, 'STATEN ISLAND': 4, 'BRONX': 5, 'OTHER':6}
df['borough_num'] = df['Borough'].apply(lambda x:0 if borough_dict.get(x) == None else borough_dict.get(x))

enter image description here

8 个答案:

答案 0 :(得分:4)

由于有一小部分自治市镇名称要为其分配整数代码,因此将其作为一系列显式逻辑索引分配完全可以接受,例如下面的一些示例数据。

具体来说,在这种情况下,不需要尝试将自治市镇代码映射封装到dict或辅助函数或任何更高级别的applymap操作中。 DataFrame。

只是一组5个无聊的直接逻辑分配。

In [13]: df = pandas.DataFrame({
    'Borough': ["Manhattan", "Brooklyn", "Bronx", "07 Bronx", 
                "109 Staten Island", "03 Brooklyn", "04 Queens"], 
    'Value':[1, 2, 3, 4, 5, 6, 7]
})

In [14]: df
Out[14]:
             Borough  Value
0          Manhattan      1
1           Brooklyn      2
2              Bronx      3
3           07 Bronx      4
4  109 Staten Island      5
5        03 Brooklyn      6
6          04 Queens      7

In [15]: df['Borough_num'] = 6  # everything defaults to the 'other' case

In [16]: df.loc[df.Borough.str.contains("Manhattan"), 'Borough_num'] = 1

In [17]: df.loc[df.Borough.str.contains("Brooklyn"), 'Borough_num'] = 2

In [18]: df.loc[df.Borough.str.contains("Queens"), 'Borough_num'] = 3

In [19]: df.loc[df.Borough.str.contains("Staten Island"), 'Borough_num'] = 4

In [20]: df.loc[df.Borough.str.contains("Bronx"), 'Borough_num'] = 5

In [21]: df
Out[21]: 
             Borough  Value  Borough_num
0          Manhattan      1            1
1           Brooklyn      2            2
2              Bronx      3            5
3           07 Bronx      4            5
4  109 Staten Island      5            4
5        03 Brooklyn      6            2
6          04 Queens      7            3

如果您想出于某种原因封装自治市镇代码映射,可以使用简单的dict后跟循环来实现:

In [30]: borough_code = {'Manhattan': 1, 'Brooklyn': 2, 'Queens': 3,
                         'Staten Island': 4, 'Bronx': 5}

In [31]: for borough, code in borough_code.items():
    ...:     df.loc[df.Borough.str.contains(borough), 'Borough_num'] = code

除非DataFrame是巨大的,否则str.contains的重复矢量化计算与在列中映射函数无法区分,但更容易理解。

答案 1 :(得分:1)

也许写一个简单的辅助函数:

def find_borough_id(name):
    for k, v in borough_dict.items():
        if k in name:
            return v
    return 0

df['borough_num'] = df['Borough'].apply(find_borough_id)

答案 2 :(得分:1)

一种解决方案是搜索borough_dict的哪个键是x的子字符串并返回其相关值:

def get_borough_num(x):
  for key, val in borough_dict.items():
    if key in x:
       return val
  return 0
df['borough_num'] = df['Borough'].apply(get_borough_num)

另一种解决方案是假设所有行都使用borough_name作为行政区名称或以空格+行政区域名称结尾。有了这样的假设,您可以使用:

获取borough_name
x.rsplit(' ')[-1]

如果字符串包含空格,则返回最后一个空格后的字符串,否则返回整个字符串:

"Manhattan".rsplit(' ')[-1] => "Manhattan"
"blah Manhattan".rsplit(' ')[-1] => "Manhattan"

所以当结束时:

get_borough_num = lambda x: borough_dict.get(x.rsplit(' ')[-1], 0)
df['borough_num'] = df['Borough'].apply(get_borough_num)

答案 3 :(得分:1)

让我们使用Pandas str访问器和字符串函数,例如extractjoinupper和python方法map

根据@alexlaval问题设置:

borough_dict = {'MANHATTAN':1, 'BROOKLYN':2, 'QUEENS': 3, 'STATEN ISLAND': 4, 'BRONX': 5, 'OTHER':6}

并从@ely

设置
df = pd.DataFrame({
    'Borough': ["Manhattan", "Brooklyn", "Bronx", "07 Bronx", 
                "109 Staten Island", "03 Brooklyn", "04 Queens","Unknown"], 
    'Value':[1, 2, 3, 4, 5, 6, 7, 8]
})

让我们创建一个正则表达式,从dataframe列中提取自治市镇:

x = '(' + '|'.join(borough_dict.keys()) + ')'

现在,让我们使用提取和地图来获得自治市镇号

df['Borough_number'] = df.Borough.str.upper()\
                         .str.extract(x, expand=False).fillna('OTHER')\
                         .map(borough_dict)

输出:

             Borough  Value  Borough_number
0          Manhattan      1               1
1           Brooklyn      2               2
2              Bronx      3               5
3           07 Bronx      4               5
4  109 Staten Island      5               4
5        03 Brooklyn      6               2
6          04 Queens      7               3
7            Unknown      8               6

答案 4 :(得分:-1)

一种天真的方法是定义一个函数来搜索字符串,如果找到该字符串,则返回预期的id。

from PIL import Image
import os


path = 'C:/Users/name/Sourcelocation/'
imagenames = os.listdir(path)

for imagename in imagenames:
    print(imagename)
try:
    im = Image.open(path + imagename)
    im.save(path + imagename)
except:
    pass

答案 5 :(得分:-1)

功能方法

使用带有生成器表达式的自定义函数,如果未找到匹配项,则使用默认值dict.get返回“OTHER”。

然后通过pd.Series.apply应用该功能。

df = pd.DataFrame({'Borough': ['07 BRONX', '01 MANHATTAN', 'STATEN ISLAND', '12 QUEENS', 'UNKNOWN']})

d = {'MANHATTAN':1, 'BROOKLYN':2, 'QUEENS': 3, 'STATEN ISLAND': 4, 'BRONX': 5, 'OTHER':6}

def map_borough(x, mapping):
    return mapping.get(next((k for k in mapping if x.endswith(k)), None), 'OTHER')

df['borough_num'] = df['Borough'].apply(map_borough, mapping=d)

print(df)

#          Borough borough_num
# 0       07 BRONX           5
# 1   01 MANHATTAN           1
# 2  STATEN ISLAND           4
# 3      12 QUEENS           3
# 4        UNKNOWN       OTHER

答案 6 :(得分:-2)

面向对象的方法

您可以继承dict,然后使用pd.Series.map

class dict_endswith(dict):
    def __getitem__(self, value):
        key = next((k for k in self.keys() if value.endswith(k)), None)
        return self.get(key)

df = pd.DataFrame({'Borough': ['07 BRONX', '01 MANHATTAN', 'STATEN ISLAND', '12 QUEENS', 'UNKNOWN']})

d = dict_endswith({'MANHATTAN':1, 'BROOKLYN':2, 'QUEENS': 3, 'STATEN ISLAND': 4, 'BRONX': 5, 'OTHER':6})

df['borough_num'] = df['Borough'].map(lambda x: d[x]).fillna('OTHER')

print(df)

#          Borough borough_num
# 0       07 BRONX           5
# 1   01 MANHATTAN           1
# 2  STATEN ISLAND           4
# 3      12 QUEENS           3
# 4        UNKNOWN       OTHER

答案 7 :(得分:-2)

Loopy解决方案

如果要使用循环,则可以通过将数据结构与逻辑分离来使代码更具可读性。

在此示例中,您可以按顺序迭代字典项。 @ely's version对于更大的数据框更好。

df = pd.DataFrame({'Borough': ['07 BRONX', '01 MANHATTAN', 'STATEN ISLAND', '12 QUEENS', 'UNKNOWN']})

d = {'MANHATTAN':1, 'BROOKLYN':2, 'QUEENS': 3, 'STATEN ISLAND': 4, 'BRONX': 5, 'OTHER':6}

def map_borough(x, mapping):
    for k, v in mapping.items():
        if k in x:
            return v
    else:
        return 'OTHER'

df['borough_num'] = df['Borough'].apply(map_borough, mapping=d)

#          Borough borough_num
# 0       07 BRONX           5
# 1   01 MANHATTAN           1
# 2  STATEN ISLAND           4
# 3      12 QUEENS           3
# 4        UNKNOWN       OTHER