R 数据操作。查找列值并进行操作
R data manipulation. Finding a column value and manipulating
我有一个这样的数据框,其中第 1 列具有不同的值并以国家/地区结尾。
Col1 col2 Col3 col4
A 0 0 1
B 1 0 3
c 4 0 6
D 5 6 7
China na na na
A 0 1 3
B 2 4 5
C 3 5 6
D 1 2 3
E 5 3 3
England na na na
我想实现类似下面的东西,所以我需要创建一个新的列,其中对国家名称进行操作,直到匹配国家名称所在的行。
Col1 col2 Col3 col4 col5
A 0 0 1 China
B 1 0 3 china
c 4 0 6 china
D 5 6 7 china
China na na na china
A 0 1 3 England
B 2 4 5 England
C 3 5 6 England
D 1 2 3 England
E 5 3 3 England
England na na na England
...另外我还有 40 个其他国家可以合作。我是 R 的新手,正在为如何实现我想要的结果而苦苦挣扎。
首先创建数据结构(以后您应该在问题中提供执行此操作的代码)。
exd <- read.table(text = "Col1 col2 Col3 col4
A 0 0 1
B 1 0 3
c 4 0 6
D 5 6 7
China NA NA NA
A 0 1 3
B 2 4 5
C 3 5 6
D 1 2 3
E 5 3 3
England NA NA NA", header = TRUE)
接下来,找出哪些行是国家边界,并提取国家名称
country_boundary <- nchar(as.character(exd$Col1)) > 1
country_names <- exd$Col1[country_boundary]
然后为每个国家/地区生成代码,逐一移动。
country_number <- c(0, cumsum(country_boundary)[-nrow(exd)])
最后,使用 country_number
和 country_names
向量创建国家 ID 列。
exd <- data.frame(exd,
Col5 = factor(country_number,
labels = country_names))
您可能希望删除(现在多余的)边界行:
exd <- exd[!country_boundary, ]
exd
# Col1 col2 Col3 col4 Col5
# 1 A 0 0 1 China
# 2 B 1 0 3 China
# 3 c 4 0 6 China
# 4 D 5 6 7 China
# 6 A 0 1 3 England
# 7 B 2 4 5 England
# 8 C 3 5 6 England
# 9 D 1 2 3 England
# 10 E 5 3 3 England
另一种 hacky 方法:使用 Col1
作为起点,使所有观察结果都具有单个字符 NA
。然后用最后一个值填充 NA
s。
library(zoo)
df$col5 = df$Col1
df$col5 = ifelse(nchar(as.character(df$col5)) > 1, as.character(df$col5), NA)
df$col5 = na.locf(as.character(df$col5), fromLast = TRUE)
一个 tidyverse 选项:
library(tidyverse)
# convert all to appropriate types
df %>% mutate_all(as.character) %>% type_convert(na = 'na') %>%
# add column with Col1 value if a row only has one non-NA value, else NA
mutate(country = ifelse(rowSums(!is.na(.)) == 1, Col1, NA)) %>%
fill(country, .direction = 'up') %>% # replace NAs upwards with last non-NA value
filter(complete.cases(.)) # subset to rows with no NAs
## Col1 col2 Col3 col4 country
## 1 A 0 0 1 China
## 2 B 1 0 3 China
## 3 c 4 0 6 China
## 4 D 5 6 7 China
## 5 A 0 1 3 England
## 6 B 2 4 5 England
## 7 C 3 5 6 England
## 8 D 1 2 3 England
## 9 E 5 3 3 England
我们可以使用 replace
和 na.locf
library(zoo)
df1$Col5 <- with(df1, na.locf(replace(Col1, nchar(Col1)==1, NA), fromLast=TRUE))
df1$Cpl5
#[1] "China" "China" "China" "China" "China" "England" "England"
#[8] "England" "England" "England" "England"
或者另一种选择是data.table
library(data.table)
setDT(df1)[, Col5 := Col1[.N], cumsum(shift(nchar(Col1)>1, fill = TRUE))]
df1
# Col1 col2 Col3 col4 Col5
# 1: A 0 0 1 China
# 2: B 1 0 3 China
# 3: c 4 0 6 China
# 4: D 5 6 7 China
# 5: China na na na China
# 6: A 0 1 3 England
# 7: B 2 4 5 England
# 8: C 3 5 6 England
# 9: D 1 2 3 England
#10: E 5 3 3 England
#11: England na na na England
我有一个这样的数据框,其中第 1 列具有不同的值并以国家/地区结尾。
Col1 col2 Col3 col4
A 0 0 1
B 1 0 3
c 4 0 6
D 5 6 7
China na na na
A 0 1 3
B 2 4 5
C 3 5 6
D 1 2 3
E 5 3 3
England na na na
我想实现类似下面的东西,所以我需要创建一个新的列,其中对国家名称进行操作,直到匹配国家名称所在的行。
Col1 col2 Col3 col4 col5
A 0 0 1 China
B 1 0 3 china
c 4 0 6 china
D 5 6 7 china
China na na na china
A 0 1 3 England
B 2 4 5 England
C 3 5 6 England
D 1 2 3 England
E 5 3 3 England
England na na na England
...另外我还有 40 个其他国家可以合作。我是 R 的新手,正在为如何实现我想要的结果而苦苦挣扎。
首先创建数据结构(以后您应该在问题中提供执行此操作的代码)。
exd <- read.table(text = "Col1 col2 Col3 col4
A 0 0 1
B 1 0 3
c 4 0 6
D 5 6 7
China NA NA NA
A 0 1 3
B 2 4 5
C 3 5 6
D 1 2 3
E 5 3 3
England NA NA NA", header = TRUE)
接下来,找出哪些行是国家边界,并提取国家名称
country_boundary <- nchar(as.character(exd$Col1)) > 1
country_names <- exd$Col1[country_boundary]
然后为每个国家/地区生成代码,逐一移动。
country_number <- c(0, cumsum(country_boundary)[-nrow(exd)])
最后,使用 country_number
和 country_names
向量创建国家 ID 列。
exd <- data.frame(exd,
Col5 = factor(country_number,
labels = country_names))
您可能希望删除(现在多余的)边界行:
exd <- exd[!country_boundary, ]
exd
# Col1 col2 Col3 col4 Col5
# 1 A 0 0 1 China
# 2 B 1 0 3 China
# 3 c 4 0 6 China
# 4 D 5 6 7 China
# 6 A 0 1 3 England
# 7 B 2 4 5 England
# 8 C 3 5 6 England
# 9 D 1 2 3 England
# 10 E 5 3 3 England
另一种 hacky 方法:使用 Col1
作为起点,使所有观察结果都具有单个字符 NA
。然后用最后一个值填充 NA
s。
library(zoo)
df$col5 = df$Col1
df$col5 = ifelse(nchar(as.character(df$col5)) > 1, as.character(df$col5), NA)
df$col5 = na.locf(as.character(df$col5), fromLast = TRUE)
一个 tidyverse 选项:
library(tidyverse)
# convert all to appropriate types
df %>% mutate_all(as.character) %>% type_convert(na = 'na') %>%
# add column with Col1 value if a row only has one non-NA value, else NA
mutate(country = ifelse(rowSums(!is.na(.)) == 1, Col1, NA)) %>%
fill(country, .direction = 'up') %>% # replace NAs upwards with last non-NA value
filter(complete.cases(.)) # subset to rows with no NAs
## Col1 col2 Col3 col4 country
## 1 A 0 0 1 China
## 2 B 1 0 3 China
## 3 c 4 0 6 China
## 4 D 5 6 7 China
## 5 A 0 1 3 England
## 6 B 2 4 5 England
## 7 C 3 5 6 England
## 8 D 1 2 3 England
## 9 E 5 3 3 England
我们可以使用 replace
和 na.locf
library(zoo)
df1$Col5 <- with(df1, na.locf(replace(Col1, nchar(Col1)==1, NA), fromLast=TRUE))
df1$Cpl5
#[1] "China" "China" "China" "China" "China" "England" "England"
#[8] "England" "England" "England" "England"
或者另一种选择是data.table
library(data.table)
setDT(df1)[, Col5 := Col1[.N], cumsum(shift(nchar(Col1)>1, fill = TRUE))]
df1
# Col1 col2 Col3 col4 Col5
# 1: A 0 0 1 China
# 2: B 1 0 3 China
# 3: c 4 0 6 China
# 4: D 5 6 7 China
# 5: China na na na China
# 6: A 0 1 3 England
# 7: B 2 4 5 England
# 8: C 3 5 6 England
# 9: D 1 2 3 England
#10: E 5 3 3 England
#11: England na na na England