pandas - 如果列标题是另一列的子字符串,则创建真/假列

Posted

技术标签:

【中文标题】pandas - 如果列标题是另一列的子字符串,则创建真/假列【英文标题】:pandas - create true/false column if column header is substring of another column 【发布时间】:2020-07-13 15:18:23 【问题描述】:

我正在关注this post,根据另一列中是否存在子字符串来创建多个真/假的列。

在使用上述帖子中的代码之前,我查看了一个名为 LANGUAGES 的字段,其中包含 "ENG, SPA, CZE""ENG, SPA" 等值。不幸的是,数据是逗号分隔的字符串而不是列表,但没问题,在一行中,我可以获得 25 个唯一值的列表。

获得唯一值列表后,我想为每个值创建一个新列,例如 df[ENG]df[SPA] 等列。我希望根据标题是否是原始 LANGUAGES 列的子字符串,这些列是真/假。

在帖子之后,我使用df.apply(lambda x: language in df.LANGUAGES, axis = 1)。但是,当我检查列的值(最后一个 for 循环中的值计数)时,所有值都为 false。

如何根据列的标题是另一列的子字符串来创建真/假列?

我的代码:

import json
import pandas as pd
import requests

url  = r"https://data.hud.gov/Housing_Counselor/search?AgencyName=&City=&State=&RowLimit=&Services=&Languages="

response = requests.get(url)

if response.status_code == 200:
    res = response.json()
    df = pd.DataFrame(res)
    df.columns = [str(h).upper() for h in list(df)]
    #
    # the below line is confusing but it creates a sorted list of all unique languages
    #
    languages = [str(s) for s in sorted(list(set((",".join(list(df["LANGUAGES"].unique()))).split(","))))]
    for language in languages:
        print(language)
        df[language] = df.apply(lambda x: language in df.LANGUAGES, axis = 1)
    for language in languages:
        print(df[language].value_counts())
        print("\n")
else:
    print("\nConnection was unsuccesful: 0".format(response.status_code))

编辑:请求提供原始数据输入和预期输出。下面是列的样子:

+-------+-----------------+
| Index |    LANGUAGES    |
+-------+-----------------+
|     0 | 'ENG, OTH, RUS' |
|     1 | 'ENG'           |
|     2 | 'ENG, CZE, SPA' |
+-------+-----------------+

这是预期的输出:

+-------+-----------------+------+-------+-------+-------+-------+
| Index |    LANGUAGES    | ENG  |  CZE  |  OTH  |  RUS  |  SPA  |
+-------+-----------------+------+-------+-------+-------+-------+
|     0 | 'ENG, OTH, RUS' | TRUE | FALSE | TRUE  | TRUE  | FALSE |
|     1 | 'ENG'           | TRUE | FALSE | FALSE | FALSE | FALSE |
|     2 | 'ENG, CZE, SPA' | TRUE | TRUE  | FALSE | TRUE  | FALSE |
+-------+-----------------+------+-------+-------+-------+-------+

【问题讨论】:

您能否将您的原始数据输入连同您的预期输出一起发布到代码块中? @Datanovice 完成 【参考方案1】:

两步,

首先,我们分解您的列表并创建一个数据透视表,以根据索引重新连接到您的原始 df。

s  = df['LANGUAGES'].str.replace("'",'').str.split(',').explode().to_frame()

cols = s['LANGUAGES'].drop_duplicates(keep='first').tolist()

df2 = pd.concat([df, pd.crosstab(s.index, s["LANGUAGES"])[cols]], axis=1).replace(
    1: True, 0: False
)
print(df2)
         LANGUAGES   ENG    OTH    RUS    CZE    SPA
0  'ENG, OTH, RUS'  True   True   True  False  False
1            'ENG'  True  False  False  False  False
2  'ENG, CZE, SPA'  True  False  False   True   True

【讨论】:

【参考方案2】:

在this post找到,我换掉了下面这行代码:

df[language] = df.apply(lambda x: language in df.LANGUAGES, axis = 1)

对于以下两行:

    criteria = lambda row : language in row["LANGUAGES"]
    df[language] = df.apply(criteria, axis =1)

而且它有效。

import json
import pandas as pd
import requests

url  = r"https://data.hud.gov/Housing_Counselor/search?AgencyName=&City=&State=&RowLimit=&Services=&Languages="

response = requests.get(url)

if response.status_code == 200:
    res = response.json()
    df = pd.DataFrame(res)
    df.columns = [str(h).upper() for h in list(df)]
    #
    # the below line is confusing but it creates a sorted list of all unique languages
    #
    languages = [str(s) for s in sorted(list(set((",".join(list(df["LANGUAGES"].unique()))).split(","))))]
    for language in languages:
        criteria = lambda row : language in row["LANGUAGES"]
        df[language] = df.apply(criteria, axis =1)
    for language in languages:
        print(df[language].value_counts())
        print("\n")
else:
    print("\nConnection was unsuccesful: 0".format(response.status_code))

这种换行也可以工作:

for language in languages:
    df[language] = df.LANGUAGES.apply(lambda x: 'True' if language in x else 'False')
    print(":".format(language, df[df[language] == 'True'].shape[0]))

【讨论】:

最好不要在 pandas 中使用 for 循环,因为它违反了 api - 使用利用底层 C /Cython 代码的矢量化方法。

以上是关于pandas - 如果列标题是另一列的子字符串,则创建真/假列的主要内容,如果未能解决你的问题,请参考以下文章

如果存在于列表中,则根据另一列的值选择列

从另一列的子字符串更新一列

编写一个 sql 查询以使用另一列的子字符串将列添加到数据框

pyspark:删除作为另一列值的子字符串,并从给定列的值中包含正则表达式字符

要检查 Pandas Dataframe 列的 TRUE/FALSE,如果 TRUE 检查另一列是不是满足条件并生成具有值 PASS/FAIL 的新列

Pandas Multiindex Groupby 聚合列与另一列的值