![](/img/trans.png)
[英]How to create a new column with sub string based on a column with long string using ifelse and grepl?
[英]Create a new column that counts the number of a sub-string in a string column?
R的新手。 我有一個要解決的問題:如果子字符串在字符串列中出現一次或多次,我需要創建一些新的列來計數1。 像這樣:
Existing Column New Col (True if apple) New Col (True if banana)
apple, apple, orange 1 0
banana, banana, orange 0 1
apple, banana, orange 1 1
有人可以幫我嗎? 提前非常感謝您。
因此,我以為您在第一次閱讀問題(上一次編輯)時需要計數列(而不是是否包含字符串),但是無論如何它都是一種有用的代碼,所以我就把它留了下來。 這是base R和stringr
軟件包的選項:
首先,讓我們制作一個樣本數據。
# stringsAsFactors = FALSE would be smart here, but let's not assume...
df <- data.frame(x = c('a, b, c, a', 'b, b, c', 'd, a'))
看起來像
> df
x
1 a, b, c, a
2 b, b, c
3 d, a
使用strsplit
列出分隔字符串的向量,並使用as.character
將因子強制轉換為有用的形式,
list <- strsplit(as.character(df$x), ', ')
然后列出唯一的字符串
lvls <- unique(unlist(list))
用sapply
data.frame / list的行。 (此答案中的所有sapply
函數都可以替換for
循環,但是出於速度原因,通常認為R中的這種樣式較差。)測試每個字符串中是否都包含唯一字符串,並更改為整數格式。 結果(設置t
ransposed)來的新列df
,每個唯一的字符串。
df[, lvls] <- t(sapply(1:nrow(df), function(z){as.integer(lvls %in% list[[z]])}))
> df
x a b c d
1 a, b, c, a 1 1 1 0
2 b, b, c 0 1 1 0
3 d, a 1 0 0 1
要將值保留為布爾值TRUE
/ FALSE
而不是整數,只需刪除as.integer
。
用外部sapply
遍歷data.frame / list的行,而內部的sapply
每一個中的唯一字符串,並通過對TRUE
值求和來計數出現次數。 結果(設置t
ransposed)來的新列df
,每個唯一的字符串。
df[, lvls] <- t(sapply(1:nrow(df), function(z){
sapply(seq_along(lvls), function(y){sum(lvls[y] == list[[z]])})
}))
> df
x a b c d
1 a, b, c, a 2 1 1 0
2 b, b, c 0 2 1 0
3 d, a 1 0 0 1
stringr
stringr
可以使這些任務更加直接。
首先,在df$x
找到唯一的字符串。 使用str_split
分割字符串(可能會影響因素),使用unlist
它們展平為向量,並找到唯一的unlist
:
library(stringr)
lvls <- unique(unlist(str_split(df$x, ', ')))
str_detect
允許我們僅循環唯一的字符串,而不是行:
df[, lvls] <- sapply(lvls, function(y){as.integer(str_detect(df$x, y))})
str_count
大大簡化了我們的語法,再次僅循環了lvls
:
df[,lvls] <- sapply(lvls, function(y){str_count(df$x, y)})
兩者的結果均與上述基數R中的結果相同。
因此,沒有完整的細節,很難確切地知道您要查找的內容。 但是,如果您要查找給定字符串出現的次數並將其作為一列添加到原始數據中,則這是一種可行的方法(復制數據輸入):
df <- data.frame(Fruit = c('apple,orange,orange', 'banana,banana,pear', 'apple,banana,orange'), stringsAsFactors = FALSE)
df$appleCount <- lapply(strsplit(df$Fruit, ','), function(x) sum('apple' == x))
df$bananaCount <- lapply(strsplit(df$Fruit, ','), function(x) sum('banana' == x))
僅當您知道確定要添加為列的特定字符串時,此方法才起作用。 但是,應該讓您了解如何分割字符串,計算該分割列表中有多少給定字符串,等等。希望這會有所幫助。
上面代碼的輸出應為:
Fruit appleCount bananaCount
1 apple,orange,orange 1 0
2 banana,banana,pear 0 2
3 apple,banana,orange 1 1
如果您不查找給定字符串出現的次數,而只是查找字符串是否出現的真/假(0/1),則可以使用此稍作修改的代碼來獲得該結果:
df <- data.frame(Fruit = c('apple,orange,orange', 'banana,banana,pear', 'apple,banana,orange'), stringsAsFactors = FALSE)
df$appleCount <- lapply(strsplit(df$Fruit, ','), function(x) 'apple' %in% x)
df$bananaCount <- lapply(strsplit(df$Fruit, ','), function(x) 'banana' %in% x)
輸出將如下所示:
Fruit appleCount bananaCount
1 apple,orange,orange TRUE FALSE
2 banana,banana,pear FALSE TRUE
3 apple,banana,orange TRUE TRUE
如果確實需要0/1,則可以使用as.integer
將邏輯列轉換為整數值。
使用@ user3949008的答案中的“ df”,也可以從我的“ splitstackshape”包中嘗試cSplit_e
:
library(splitstackshape)
cSplit_e(df, "Fruit", ",", type = "character", fill = 0)
# Fruit Fruit_apple Fruit_banana Fruit_orange Fruit_pear
# 1 apple,orange,orange 1 0 1 0
# 2 banana,banana,pear 0 1 0 1
# 3 apple,banana,orange 1 1 1 0
您以后總是可以刪除不感興趣的列。
如果您想mtabulate
,可以嘗試從“ qdapTools”進行制表:
library(qdapTools)
mtabulate(strsplit(df$Fruit, ","))
# apple banana orange pear
# 1 1 0 2 0
# 2 0 2 0 1
# 3 1 1 1 0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.