【问题标题】:Counting elements that satisfy a criteria in a dataset- Python/pandas计算满足数据集中条件的元素 - Python/pandas
【发布时间】:2021-10-28 11:59:43
【问题描述】:

在一个数据集中,我有四列名为 TP1、TP2 等(代表测试阶段 1,2...)。这些列中的信息可以是以下 5 种之一:Not_tested、Not_finished、too_low、150 到 190 之间的值,以及什么都没有。

当一个元素在 4 列中的任何一列中至少显示一次时,该元素被视为已测试:too_low 或介于 150 和 190 之间的值。如果该元素的行中的任何点均未显示这 2 个值,则认为未测试。

我需要报告以下内容:

“测试元素的数量:43(以及所有元素的百分比)”(相当于有多少行显示 too_low 或 150 到 190 之间的值)

“新测试元素的数量:# 和 %”(所以从上面找到的元素中,NEW 列中有 YES?)

“旧测试元素的数量:# 和 %”(取而代之的是 NO)

部分数据集的示例如下所示:

+=======+==========+=====+======+==============+=========+==============+=====+
|  ID   | Location | NEW | YEAR |     PT1      |   PT2   |     PT3      | PT4 |
+=======+==========+=====+======+==============+=========+==============+=====+
| GF342 | Q1       | YES | 2021 |              |         |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| IF874 | Q3       | NO  | 2018 | NOT_TESTED   |         | TOO_LOW      |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| FH386 | Q1       | NO  | 2019 |              |         |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| KJ190 | Q3       | YES | 2021 | NOT_FINISHED |         | TOO_LOW      |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| TY748 | Q3       | YES | 2021 |              |         |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| YT947 | Q4       | NO  | 2019 |              | TOO_LOW |              | 165 |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| DF063 | Q3       | NO  | 2019 | 180          |         |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| ET512 | Q1       | YES | 2021 |              |         |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| GC714 | Q2       | NO  | 2018 |              | 160     |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| SD978 | Q3       | NO  | 2019 |              | TOO_LOW |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| EF472 | Q1       | NO  | 2018 |              |         |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| PL489 | Q2       | YES | 2021 |              |         | NOT_FINISHED |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| AZ315 | Q1       | NO  | 2018 | TOO_LOW      |         |              | 180 |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| OL821 | Q1       | YES | 2021 |              |         | 185          |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| HN765 | Q3       | YES | 2021 | 155          |         |              |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+
| ED589 | Q1       | YES | 2021 |              |         | 165          |     |
+-------+----------+-----+------+--------------+---------+--------------+-----+

我解决这个问题的想法是使用包含必要值的所有行的 .sum() ,但是我如何制定一个规则,即只有在这些值存在时才计算它?我是否可以使用 T 或 F 在数据框中添加一个新列,具体取决于它是否满足具有 too_low 或数字(150-190)的规则。我对这一切都很陌生,不知道该怎么做。我不一定要直接回答,但如果可能的话,请对问题提供一些指导,谢谢。

数据框:

pd.DataFrame({'ID': {0: 'GF342',  1: 'IF874',  2: 'FH386',  3: 'KJ190',  4: 'TY748',  5: 'YT947',  6: 'DF063',  7: 'ET512',  8: 'GC714',  9: 'SD978',  10: 'EF472',  11: 'PL489',  12: 'AZ315',  13: 'OL821',  14: 'HN765',  15: 'ED589'}, 'Location': {0: 'Q1',  1: 'Q3',  2: 'Q1',  3: 'Q3',  4: 'Q3',  5: 'Q4',  6: 'Q3',  7: 'Q1',  8: 'Q2',  9: 'Q3',  10: 'Q1',  11: 'Q2',  12: 'Q1',  13: 'Q1',  14: 'Q3',  15: 'Q1'}, 'NEW': {0: 'YES',  1: 'NO',  2: 'NO',  3: 'YES',  4: 'YES',  5: 'NO',  6: 'NO',  7: 'YES',  8: 'NO',  9: 'NO',  10: 'NO',  11: 'YES',  12: 'NO',  13: 'YES',  14: 'YES',  15: 'YES'}, 'YEAR': {0: 2021,  1: 2018,  2: 2019,  3: 2021,  4: 2021,  5: 2019,  6: 2019,  7: 2021,  8: 2018,  9: 2019,  10: 2018,  11: 2021,  12: 2018,  13: 2021,  14: 2021,  15: 2021}, 'PT1': {0: '',  1: 'NOT_TESTED',  2: '',  3: 'NOT_FINISHED',  4: '',  5: '',  6: '180',  7: '',  8: '',  9: '',  10: '',  11: '',  12: 'TOO_LOW',  13: '',  14: '155',  15: ''}, 'PT2': {0: '',  1: '',  2: '',  3: '',  4: '',  5: 'TOO_LOW',  6: '',  7: '',  8: '160',  9: 'TOO_LOW',  10: '',  11: '',  12: '',  13: '',  14: '',  15: ''}, 'PT3': {0: '',  1: 'TOO_LOW',  2: '',  3: 'TOO_LOW',  4: '',  5: '',  6: '',  7: '',  8: '',  9: '',  10: '',  11: 'NOT_FINISHED',  12: '',  13: '185',  14: '',  15: '165'}, 'PT4': {0: '',  1: '',  2: '',  3: '',  4: '',  5: 165.0,  6: '',  7: '',  8: '',  9: '',  10: '',  11: '',  12: 180.0,  13: '',  14: '',  15: ''}})

【问题讨论】:

  • 能否提供pd.DataFrame()格式的数据?
  • pd.Dataframe({'ID': {0L: 'GF342', 1L: 'IF874', 2L: 'FH386', 3L: 'KJ190', 4L: 'TY748'}, 'Location': {0L: 'Q1', 1L: 'Q3', 2L: 'Q1', 3L: 'Q3', 4L: 'Q3'}, 'YEAR': {0L: 2021L, 1L: 2018L, 2L: 2019L, 3L: 2021L, 4L: 2021L}, 'NEW': {0L: 'YES', 1L: 'NO', 2L: 'NO', 3L: 'YES', 4L: 'YES'}, 'PT4': {0L: nan, 1L: nan, 2L: nan, 3L: nan, 4L: nan}, 'PT3': {0L: nan, 1L: 'TOO_LOW', 2L: nan, 3L: 'TOO_LOW', 4L: nan}, 'PT2': {0L: nan, 1L: nan, 2L: nan, 3L: nan, 4L: nan}, 'PT1': {0L: nan, 1L: 'NOT_TESTED', 2L: nan, 3L: 'NOT_FINISHED', 4L: nan}}) 我希望这就是你的意思。

标签: python pandas python-2.7 dataset


【解决方案1】:

你可以试试这样的

df = pd.DataFrame([['NO',  'NOT_TESTED', None, 'TOO_LOW', None],
                  ['YES',  'NOT_FINISHED ', None, 'TOO_LOW', None],
                  ['YES', None, None, None, None],
                  ['NO', 180, None, None, None],
                  ['NO', 'TOO_LOW', None, None, 180],
                  ['YES', 155.6, None, None, None]], columns=['NEW', 'PT1', 'PT2', 'PT3', 'PT4'])

# Number of tested elements: 43 (and a percentage from all elements)"
# (which equates to how many rows show too_low or a value between 150 and 190)
filter_ = df.loc[:, 'PT1':'PT4']\
            .apply(lambda x: x.eq('TOO_LOW') | x.astype(str).str.fullmatch(r'\d+\.*\d*'), axis=0)\
            .any(axis=1)

number_of_tested = filter_.sum()


#"Number of new tested elements
new_tested_elements = df[filter_ & df['NEW'].eq('YES')].shape[0]


#"Number of old tested elements
old_tested_elements = df[filter_ & df['NEW'].eq('NO')].shape[0]

【讨论】:

  • 谢谢,这很有帮助。我收到一条错误消息:'AttributeError: ("'StringMethods' object has no attribute 'fullmatch'", u'occurred at index PT1')' 这是因为我使用的是 python 2.7 吗? (我对这个版本别无选择,因为这是我必须遵守的约束)
  • 然后使用.match
【解决方案2】:

我假设您正在使用 Pandas 库中的 DataFrame。我遇到了类似的问题并遍历了数据框。变量 df 是我使用 Pandas 的“read_csv”方法从 CSV 中提取的数据帧。我不知道您如何获取数据集,但它应该是类似的格式。我希望它对你有用,或者至少你能找到一种方法

tooLow = "TOO_LOW"
elementsCount = 0
index = len(df.columns)

for r in range(len(df.index)):
    for c in range(index):
        columnValue = df.at[r, df.columns[c]]
        if  (150 <= columnValue <= 190) or (columnValue == tooLow):
            elementsCount += 1

print("Elements satisfying criteria: ", elementsCount)

【讨论】:

  • 这种方法一开始似乎有效,但实际上,它只计算too_low在整个数据集中出现的次数。不知道为什么,所以我正在努力。为了澄清,每个元素(行)要么经过测试,要么不经过测试。测试 150-190 的值是否出现在 TP1 到 TP4 列中的任何点。例如,如果它同时出现在 TP1 和 TP2 中,则不会测试两次,仅测试一次。如果它在 TP1 到 TP4 中的某个点显示 too_low,也会对其进行测试,而不管其他列中的内容。例如,如果某个元素在 TP1 中显示 165,在 TP3 中显示 too_low,则认为该元素已测试。
猜你喜欢
  • 2018-07-26
  • 2021-02-05
  • 2019-01-17
  • 2019-11-14
  • 1970-01-01
  • 2016-05-09
  • 1970-01-01
  • 2020-04-01
  • 2018-09-20
相关资源
最近更新 更多